I got a list like this:
host_depends:
- host: abc
depends:
- name: item1
- name: item4
type: asdf
- name: item6
- host: def
depends:
- name: item2
- name: item4
- name: item6
I need to loop over the unique name of the depends
elemnents, so in this example I want to loop over
- item1
- item2
- item4
- item6
Basically what
debug: var=item.1.name
with_subelements:
- "{{ host_depends }}"
- depends
does, but with unique elements only.
How can I get the depends
of all host_depends
items so I can run a unique
filter over them and use them with with_items
?
Edit:
I manage to get a list of all depends
items like this:
host_depends|map(attribute='depends')|list
But from there, I fail to reduce this list to the name
items.
If things get too complicated with Ansible and you can't map you mind around it, it's an indicator that it shouldn't be done. Maybe it's possible with some Jinja filters and some set_fact
tasks in a loop. But don't, Ansible is not a programming language and should not be used as such. Ansible has two main strengths: readability and extensibility. Don't break the first by ignoring the latter.
with_subelements
is in fact a plugin itself, just that it is a core plugin. Just copy it and create your own with_unique_subelements
plugin. Here is the code of with_subelements. Line 100 is where the elements are added to the return list. That's where you can hook in and implement a check if that item already was added.
Save your modified version relative to your playbook as lookup_plugins/unique_subelements.py
or if you use Ansible 2 you can also store it with the same path inside any role.
host_depends|map(attribute='depends')|list
returns a list of lists, as depends is a list. To flatten/combine this list of lists into one list, use the builtin flatten lookup:
lookup('flattened', host_depends|map(attribute='depends')) |map(attribute='name')|unique|list
host_depends|map(attribute='depends')|list
returns a list of lists, as depends
is a list.
To flatten/combine this list of lists into one list:
Add this as roles/<rolename>/filter_plugins/filter.py
:
from ansible import errors
# This converts a list of lists into a single list
def flattenlist(l):
try:
return [item for sublist in l for item in sublist]
except Exception, e:
raise errors.AnsibleFilterError('split plugin error: %s' % str(e) )
class FilterModule(object):
''' A filter to split a string into a list. '''
def filters(self):
return {
'flattenlist' : flattenlist
}
And use
host_depends|map(attribute='depends')|flattenlist|map(attribute='name')|unique|list