Skip to content

Commit

Permalink
[WIP] Start of subelements filter (#39829)
Browse files Browse the repository at this point in the history
* Start of subelements filter

* Add docs for subelements filter
  • Loading branch information
sivel authored and bcoca committed May 23, 2018
1 parent 46fbfd5 commit a5f05c6
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
59 changes: 59 additions & 0 deletions docs/docsite/rst/user_guide/playbooks_filters.rst
Expand Up @@ -184,6 +184,65 @@ into::
- key: Environment
value: dev

subelements Filter
``````````````````

.. versionadded:: 2.7

Produces a product of an object, and subelement values of that object, similar to the ``subelements`` lookup::

{{ users|subelements('groups', skip_missing=True) }}

Which turns::

users:
- name: alice
authorized:
- /tmp/alice/onekey.pub
- /tmp/alice/twokey.pub
groups:
- wheel
- docker
- name: bob
authorized:
- /tmp/bob/id_rsa.pub
groups:
- docker

Into::

-
- name: alice
groups:
- wheel
- docker
authorized:
- /tmp/alice/onekey.pub
- wheel
-
- name: alice
groups:
- wheel
- docker
authorized:
- /tmp/alice/onekey.pub
- docker
-
- name: bob
authorized:
- /tmp/bob/id_rsa.pub
groups:
- docker
- docker

An example of using this filter with ``loop``::

- name: Set authorized ssh key, extracting just that data from 'users'
authorized_key:
user: "{{ item.0.name }}"
key: "{{ lookup('file', item.1) }}"
loop: "{{ users|subelements('authorized') }}"

.. _random_filter:

Random Number Filter
Expand Down
47 changes: 47 additions & 0 deletions lib/ansible/plugins/filter/core.py
Expand Up @@ -473,6 +473,52 @@ def flatten(mylist, levels=None):
return ret


def subelements(obj, subelements, skip_missing=False):
'''Accepts a dict or list of dicts, and a dotted accessor and produces a product
of the element and the results of the dotted accessor
>>> obj = [{"name": "alice", "groups": ["wheel"], "authorized": ["/tmp/alice/onekey.pub"]}]
>>> subelements(obj, 'groups')
[({'name': 'alice', 'groups': ['wheel'], 'authorized': ['/tmp/alice/onekey.pub']}, 'wheel')]
'''
if isinstance(obj, dict):
element_list = list(obj.values())
elif isinstance(obj, list):
element_list = obj[:]
else:
raise AnsibleFilterError('obj must be a list of dicts or a nested dict')

if isinstance(subelements, list):
subelement_list = subelements[:]
elif isinstance(subelements, string_types):
subelement_list = subelements.split('.')
else:
raise AnsibleFilterError('subelements must be a list or a string')

results = []

for element in element_list:
values = element
for subelement in subelement_list:
try:
values = values[subelement]
except KeyError:
if skip_missing:
values = []
break
raise AnsibleFilterError("could not find %r key in iterated item %r" % (subelement, values))
except TypeError:
raise AnsibleFilterError("the key %s should point to a dictionary, got '%s'" % (subelement, values))
if not isinstance(values, list):
raise AnsibleFilterError("the key %r should point to a list, got %r" % (subelement, values))

for value in values:
results.append((element, value))

return results


def dict_to_list_of_dict_key_value_elements(mydict):
''' takes a dictionary and transforms it into a list of dictionaries,
with each having a 'key' and 'value' keys that correspond to the keys and values of the original '''
Expand Down Expand Up @@ -574,4 +620,5 @@ def filters(self):
'extract': extract,
'flatten': flatten,
'dict2items': dict_to_list_of_dict_key_value_elements,
'subelements': subelements,
}

0 comments on commit a5f05c6

Please sign in to comment.