Доступ к значению указанного ключа словаря в списке словарей в 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 ответ
Есть много вариантов. Выберите тот, который лучше всего подходит для вашего случая использования.
- Создать словарь
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']
- Создать список измененных пакетов
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]
- Создайте список и сопоставьте базовое имя
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)