используйте select и map с ansible

Вопрос или проблема

У меня есть словарь, и я хотел бы выбрать все элементы, имеющие 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

  1. Использование selectattr для фильтрации: selectattr позволяет выбрать элементы списка по значению указанного атрибута.
  2. Использование map для получения списка значений: Затем применяем map, чтобы извлечь значение size_FS из отфильтрованного списка.
  3. Суммирование значений: В конце применяется 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 также может пригодиться в случаях, когда требуется более комплексная фильтрация. Оба способа обеспечивают простоту в написании и понимании кода, позволяя сосредоточиться на решении задач автоматизации.

Оцените материал
Добавить комментарий

Капча загружается...