Вопрос или проблема
У меня есть словарь, и я хотел бы выбрать все элементы, имеющие vg_name == 'vgapplis'
, и вычислить сумму их size_FS
. Я пробовал это, но оно не работает. Есть идеи?
- set_fact:
FS_vgapplis:"{{ FS | select(''search'', ''\bvgapplis\b'')| map(attribute="size_FS")|list|sum }}"
Вот как выглядит моя переменная FS
FS:
- nom_FS: /appm/oracle/product
nom_LV: lv_product
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /appm/oracle/product/12.1.0.2
nom_LV: lv_12102
size_FS: 15
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /apps/oracle/logs
nom_LV: lvlogs
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vglogs
Спасибо
Вы неправильно используете фильтр select
с довольно странным аргументом (я подозреваю, что это ошибка копирования/вставки, но не уверен). select
применит тест к каждому объекту в списке. Я не знаю никаких search
тестов, которые можно применить к хеш-таблице (ближайшее, что я могу представить, это метод search
в python для объекта re
– то есть регулярное выражение, что в любом случае не было бы уместно)
В вашем случае вы ищете конкретное значение атрибута вашей хеш-таблицы. Это можно сделать с помощью фильтра selectattr
, который применит тест к данному атрибуту объектов в списке и вернет только те, которые прошли тест.
Существует другой подход к вашей проблеме, который, на мой взгляд, более компактный, используя фильтр json_query
Ниже приведен пример плейбука, использующего оба подхода, приводящего к одному и тому же результату.
---
- name: Сумма размера FS
hosts: localhost
gather_facts: false
vars:
FS:
- nom_FS: /appm/oracle/product
nom_LV: lv_product
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /appm/oracle/product/12.1.0.2
nom_LV: lv_12102
size_FS: 15
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /apps/oracle/logs
nom_LV: lvlogs
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vglogs
tasks:
- name: Вычислить с использованием selectattr, map и sum
debug:
msg: "{{ FS | selectattr('vg_name', '==', 'vgapplis') | map(attribute="size_FS") | list | sum }}"
- name: Вычислить с использованием json_query
vars:
sum_query: "[?vg_name=='vgapplis'].size_FS | sum(@)"
debug:
msg: "{{ FS | json_query(sum_query) }}"
И результат
PLAY [Сумма размера FS] ****************************************************************
TASK [Вычислить с использованием selectattr, map и sum] ****************************************
ok: [localhost] => {
"msg": "20"
}
TASK [Вычислить с использованием json_query] *****************************************************
ok: [localhost] => {
"msg": "20"
}
PLAY RECAP ***************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Ответ или решение
Как использовать select и map в Ansible для вычисления суммы значений в словаре
Вопрос относительно использования фильтров select и map в Ansible для фильтрации данных из словаря часто возникает среди IT-специалистов, работающих с автоматизацией через Ansible. В данном случае требуется извлечь элементы из списка словарей, у которых значение поля vg_name
равно 'vgapplis'
, и вычислить сумму значений поля size_FS
. Рассмотрим правильный подход к решению этой задачи на примере.
Пример задачи
А у вас уже есть переменная FS, представляющая собой список словарей, в которой мы должны производить вычисления:
FS:
- nom_FS: /appm/oracle/product
nom_LV: lv_product
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /appm/oracle/product/12.1.0.2
nom_LV: lv_12102
size_FS: 15
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /apps/oracle/logs
nom_LV: lvlogs
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vglogs
Ваш исходный код содержащий использование select
был некорректным, так как фильтр select
применялся с перечислением, что не подходит для выбора из словарей. Вместо этого мы можем использовать фильтр selectattr
, который позволяет явно выбирать элементы по значению их атрибутов.
Корректное решение
Применение selectattr и map
- Использование
selectattr
для фильтрации:selectattr
позволяет выбрать элементы списка по значению указанного атрибута. - Использование
map
для получения списка значений: Затем применяемmap
, чтобы извлечь значениеsize_FS
из отфильтрованного списка. - Суммирование значений: В конце применяется
sum
для вычисления итоговой суммы.
Ниже приведен пример Ansible плейбука, который демонстрирует это:
---
- name: Sum size of FS
hosts: localhost
gather_facts: false
vars:
FS:
- nom_FS: /appm/oracle/product
nom_LV: lv_product
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /appm/oracle/product/12.1.0.2
nom_LV: lv_12102
size_FS: 15
owner_FS: oracle
group_FS: dba
vg_name: vgapplis
- nom_FS: /apps/oracle/logs
nom_LV: lvlogs
size_FS: 5
owner_FS: oracle
group_FS: dba
vg_name: vglogs
tasks:
- name: Calculate with selectattr, map and sum
debug:
msg: "{{ FS | selectattr('vg_name', '==', 'vgapplis') | map(attribute='size_FS') | list | sum }}"
Применение json_query
Есть альтернатива — использование фильтра json_query для более компактного написания запроса. Для фильтрации и суммирования используйте следующий код:
- name: Calculate with json_query
vars:
sum_query: "[?vg_name=='vgapplis'].size_FS | sum(@)"
debug:
msg: "{{ FS | json_query(sum_query) }}"
Результаты
При выполнении этого плейбука мы получим ожидаемый результат:
ok: [localhost] => {
"msg": "20"
}
Таким образом, суммарный размер файловых систем с vg_name
равным vgapplis
составляет 20.
Заключение
Используя фильтры selectattr
и map
, мы можем легко и эффективно обрабатывать данные в Ansible. Альтернативный подход с json_query
также может пригодиться в случаях, когда требуется более комплексная фильтрация. Оба способа обеспечивают простоту в написании и понимании кода, позволяя сосредоточиться на решении задач автоматизации.