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

Доступ к значению указанного ключа словаря в списке словарей в 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)

Связанный контент