Ansible со значением по умолчанию для подэлементов

у меня есть определение vars, как это:

sites:
 - site: mysite1.com
   exec_init:
    - "command1 to exec"
    - "command2 to exec"
 - site: mysite2.com

тогда у меня есть игра со следующей задачей

- name: Execute init scripts for all sites
  shell: "{{item.1}}"
  with_subelements: 
    - sites
    - exec_init
  when: item.0.exec_init is defined

идея здесь в том, что у меня будет несколько определений "сайта" с десятками других свойств в моих vars, затем я хотел бы выполнить несколько команд сценария оболочки для тех сайтов, у которых "exec_init" определен

делая это таким образом, он просто всегда пропускает выполнение задачи, я пробовал это во всех комбинациях, которые я могу себе представить, но я просто не могу получить это сработает...

это правильный способ сделать это? может быть, я пытаюсь достичь чего-то, что не имеет смысла?

Спасибо за помощь

4 ответов


Hm, похоже, имеет неоднородную структуру для элементов в sites что-то with_subelements не нравится. А также, что item не содержит подэлемент, указанный в списке with_subelements. Вы можете сделать несколько вещей:

  1. убедитесь, что есть exec_init список, даже если он пустой. with_subelements пропускает элементы с пустыми подэлементами. Я думаю, что это лучший вариант, хотя немного неудобно при написании план.

  2. не используйте with_subelements и batch execute yourself (немного некрасиво):

    - name: Execute init scripts for all sites
      shell: "echo '{{item.exec_init | join(';')}}' | bash"
      when: item.exec_init is defined
      with_items: sites
    
  3. настройка with_subelements чтобы это были элементы с отсутствующим подэлементом. Вы можете скопировать оригинал (мой в /usr/local/lib/python2.7/dist-packages/ansible/runner/lookup_plugins/with_subelements.py) и положить его в lookup_plugins каталог рядом с вашей playbook, под другим именем (скажем subelements_missingok.py). Затем измените строку 59 от:

    raise errors.AnsibleError("could not find '%s' key in iterated item '%s'" % (subelement, item0))
    

    в:

    continue
    

    тогда ваша задача может выглядеть так это:

    - name: Execute init scripts for all sites
      debug: "msg={{item.1}}"
      with_subelements_missingok:
        - sites
        - exec_init
    

есть другой способ, попробуйте:

- debug: "var=item"
  with_subelements:
    - "{{ sites | selectattr('exec_init', 'defined') | list }}"
    - exec_init

спасибо: https://github.com/PublicaMundi/ansible-plugins/blob/master/lookup_plugins/subelements_if_exist.py


и еще один способ, с флагом skip_missing (Ansible 2.0+):

- name: nested loop skip missing elements
  with_subelements:
    - sites
    - exec_init
    - flags:
      skip_missing: true

это работает для меня. Я использую версию 2.1.1 Просто добавьте третий элемент в список подэлементов, как показано

- name: Iterate over something
  with_subelements:
     - "{{ unit }}"
     - config
     - skip_missing: True