Reputation: 1306
i have a vars definition like this:
sites:
- site: mysite1.com
exec_init:
- "command1 to exec"
- "command2 to exec"
- site: mysite2.com
then i have play with the following task
- name: Execute init scripts for all sites
shell: "{{item.1}}"
with_subelements:
- sites
- exec_init
when: item.0.exec_init is defined
The idea here is that i will have multiple "Site" definitions with dozens of other properties in my vars, then i would like to execute multiple Shell script commands for those sites having "exec_init" defined
Doing it this way it just always skip executing the task, i've tried this in all combinations i can imagine but i just can't get it to work...
Is this the proper way of doing it? maybe i'm trying to achieve something that doesn't make sense?
Thanks for your help
Upvotes: 12
Views: 10622
Reputation: 140
The valid solution here (considering ansible 2.7+) is to use loop
instead of with_subelements
. As with loop you can apply subelements
filter, that has skip_missing
option (ie what @hkariti suggested in option 3 but in proper way).
So, code should look like:
- name: Execute init scripts for all sites
shell: "{{ item.1 }}"
loop: "{{ sites | subelements('exec_init', skip_missing=True) }}"
Upvotes: 7
Reputation: 41
This works for me. I am using version 2.1.1 Just add the third element in the subelements list as shown
- name: Iterate over something with_subelements: - "{{ unit }}" - config - skip_missing: True
Upvotes: 4
Reputation: 3196
And yet another way, with the skip_missing flag (Ansible 2.0+):
- name: nested loop skip missing elements
with_subelements:
- sites
- exec_init
- flags:
skip_missing: true
Upvotes: 5
Reputation: 191
There's another way, try:
- debug: "var=item"
with_subelements:
- "{{ sites | selectattr('exec_init', 'defined') | list }}"
- exec_init
Thanks to: https://github.com/PublicaMundi/ansible-plugins/blob/master/lookup_plugins/subelements_if_exist.py
Upvotes: 19
Reputation: 1719
Hm, looks like having a non-uniform structure for the elements in sites
is something with_subelements
doesn't like. And also that item
doesn't contain the subelement you specified in the with_subelements list. You can do several things:
Make sure to have an exec_init
list, even if it's empty. with_subelements
will skip items with empty subelements. I think this is the best option, although a bit inconvenient when writing the playbook.
Don't use with_subelements
and batch execute yourself (a bit ugly):
- name: Execute init scripts for all sites
shell: "echo '{{item.exec_init | join(';')}}' | bash"
when: item.exec_init is defined
with_items: sites
Customize with_subelements
so that it would items with the missing subelement. You can copy the original (mine is in /usr/local/lib/python2.7/dist-packages/ansible/runner/lookup_plugins/with_subelements.py
) and put it in a lookup_plugins
directory next to your playbook, under a different name (say subelements_missingok.py
). Then change line 59 from:
raise errors.AnsibleError("could not find '%s' key in iterated item '%s'" % (subelement, item0))
to:
continue
Then your task can look like this:
- name: Execute init scripts for all sites
debug: "msg={{item.1}}"
with_subelements_missingok:
- sites
- exec_init
Upvotes: 6