Доступ к значению указанного ключа словаря в списке словарей в Ansible

Я устанавливаю список пакетов в переменную регистрации ansible и вывожу его с помощьюdebug:

        community.general.homebrew:
    name: "{{ package }}"
    state: present
  register: package_install
  until: package_install is succeeded
  loop:
    - pam-reattach
    - pinentry-mac
    - jorgelbg/tap/pinentry-touchid
  loop_control:
    loop_var: package

- debug:
    msg: "{{ package_install }}"

Вывод выглядит следующим образом:
      msg:
  changed: true
  msg: All items completed
  results:
  - ansible_loop_var: package
    attempts: 1
    changed: false
    changed_pkgs: []
    failed: false
    invocation:
      module_args:
        install_options: []
        name:
        - pam-reattach
        path: /usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin
        state: present
        update_homebrew: false
        upgrade_all: false
        upgrade_options: []
    msg: 'Package already installed: pam-reattach'
    package: pam-reattach
    unchanged_pkgs:
    - pam-reattach
  - ansible_loop_var: package
    attempts: 1
    changed: true
    changed_pkgs:
    - pinentry-mac
    failed: false
    invocation:
      module_args:
        install_options: []
        name:
        - pinentry-mac
        path: /usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin
        state: present
        update_homebrew: false
        upgrade_all: false
        upgrade_options: []
    msg: 'Package installed: pinentry-mac'
    package: pinentry-mac
    unchanged_pkgs: []
  - ansible_loop_var: package
    attempts: 1
    changed: true
    changed_pkgs:
    - jorgelbg/tap/pinentry-touchid
    failed: false
    invocation:
      module_args:
        install_options: []
        name:
        - jorgelbg/tap/pinentry-touchid
        path: /usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin
        state: present
        update_homebrew: false
        upgrade_all: false
        upgrade_options: []
    msg: 'Package installed: jorgelbg/tap/pinentry-touchid'
    package: jorgelbg/tap/pinentry-touchid
    unchanged_pkgs: []
  skipped: false

Зарегистрированная переменнаяpackage_install.resultsсодержит список словарей (или карт/хешей — пожалуйста, поправьте меня, если я ошибаюсь) с данными, относящимися к каждомуpackageмонтаж.

Мне нужно проверить, есть лиpinentry-macилиpinentry-touchidпакеты были установлены во время предыдущей задачи (значениеchangedключ внутри каждого элемента равенtrueилиfalse), и если да, то запустите указанную команду, например:

      - command: <command>
  when: >
    `pinentry-mac` item's attribute `changed` is `True` within `package_install.results` \
    OR \
    `pinentry-touchid` item's attribute `changed` is `True` within `package_install.results`

Как бы я это сделал?

Прямо сейчас я делаю следующее:

        - command: <command>
    when: "'pinentry' in item.package and item.changed"
    loop: "{{ macterm_package_install.results }}"

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

Есть ли способ сделать это правильно? Любые мысли высоко ценятся.

ОБНОВЛЯТЬ

«Лучший» способ, который мне удалось найти, это (в два этапа):

        - name: Check if any of the pinentry packages were installed during previous tasks
    set_fact:
      pinentry_changed: True
    when: "'pinentry-' in item.package and item.changed"
    loop: "{{ macterm_package_install.results }}"

  - command: <command>
    when: pinentry_changed | default(false)

Но действительно, есть ли более элегантный способ решить эту проблему?

1 ответ

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

  1. Создать словарь
        package_changed: "{{ package_install.results|
                       items2dict(key_name='package', value_name='changed') }}"

дает

        package_changed:
    jorgelbg/tap/pinentry-touchid: true
    pam-reattach: false
    pinentry-mac: true

Тогда условия тривиальны

          - command: <command>
      when:  package_changed['pinentry-mac'] or
             package_changed['jorgelbg/tap/pinentry-touchid']
  1. Создать список измененных пакетов
        changed_pkgs: "{{ package_install.results|
                    map(attribute='changed_pkgs')|flatten }}"

дает

        changed_pkgs:
  - pinentry-mac
  - jorgelbg/tap/pinentry-touchid

Либо протестируйте каждый пакет

          - command: <command>
      when:  ('pinentry-mac' in changed_pkgs) or
             ('jorgelbg/tap/pinentry-touchid' in changed_pkgs)

или пересечь списки, если вы можете поместить протестированные пакеты в список

          - command: <command>
      when:  changed_pkgs|intersect(test_pkgs)|length > 0
      vars:
        test_pkgs: [pinentry-mac, jorgelbg/tap/pinentry-touchid]
  1. Создайте список и сопоставьте базовое имя
        changed_pkgs: "{{ package_install.results|
                    map(attribute='changed_pkgs')|flatten|
                    map('basename')|list }}"

дает

        changed_pkgs:
  - pinentry-mac
  - pinentry-touchid

Используйте только имена пакетов

          - command: <command>
      when:  ('pinentry-mac' in changed_pkgs) or
             ('pinentry-touchid' in changed_pkgs)
Другие вопросы по тегам