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

share|improve this question
up vote 4 down vote accepted

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:

  1. 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.

  2. 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
    
  3. 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
    
share|improve this answer

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

share|improve this answer

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
share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.