Вопрос или проблема
Я пытаюсь динамически перебрать количество записей в массиве и использовать результат в качестве индекса.
Думаю, я делаю что-то не так.
Как можно присвоить переменной значение конца последовательности, которое представляет количество текущего массива?
ansible-playbook 2.9.6
run.yml:
---
- hosts: localhost
tasks:
- name: Импорт конфигурации
include_vars:
file: ./config.yml
- name: ОТЛАДКА
debug: msg="{{ item[0].team_name }}: {{ item[0].applications.name }}: индекс: {{ item[1] }}"
with_nested:
- "{{ teams }}"
- "{{ lookup('sequence', 'start=1 end='+(item[0].applications|length))|string }}"
config.yml:
teams:
- team_name: Название-Команды_A
applications:
- name: имя_приложения_a
- name: имя_приложения_b
- team_name: Название-Команды_B
applications:
- name: имя_приложения_c
- name: имя_приложения_d
Выполнение:
ansible-playbook run.yml
PLAY [localhost] ********************************************************************************************************************************************************************
TASK [Сбор фактов] **************************************************************************************************************************************************************
ok: [localhost]
TASK [Импорт конфигурации] ********************************************************************************************************************************************************
ok: [localhost]
TASK [ОТЛАДКА] ************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'item' is undefined"}
PLAY RECAP **************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Желаемый результат:
msg: 'Название-Команды_A: имя_приложения_a: индекс: 1'
msg: 'Название-Команды_A: имя_приложения_b: индекс: 2'
msg: 'Название-Команды_B: имя_приложения_c: индекс: 1'
msg: 'Название-Команды_B: имя_приложения_d: индекс: 2'
Ответ: Например, задача ниже
- debug:
msg: "{{ item.0.team_name }}: {{ item.1.name }}: {{ index1|int + 1 }}"
with_subelements:
- "{{ teams }}"
- applications
vars:
team_names: "{{ teams|
map(attribute="team_name")|
list }}"
index0: "{{ team_names.index(item.0.team_name) }}"
applications: "{{ teams|
map(attribute="applications")|
list }}"
application_names: "{{ applications[index0|int]|
map(attribute="name")|
list }}"
index1: "{{ application_names.index(item.1.name) }}"
дает
msg: 'Название-Команды_A: имя_приложения_a: 1'
msg: 'Название-Команды_A: имя_приложения_b: 2'
msg: 'Название-Команды_B: имя_приложения_c: 1'
msg: 'Название-Команды_B: имя_приложения_d: 2'
Это решение ограничено уникальными списками.
Лучшей структурой для этого случая является словарь. Например, задача ниже дает те же результаты
- debug:
msg: "{{ item.0.key }}: {{ item.1 }}: {{ teams[item.0.key].index(item.1) + 1 }}"
with_subelements:
- "{{ teams|dict2items }}"
- value
vars:
teams:
Название-Команды_A:
- имя_приложения_a
- имя_приложения_b
Название-Команды_B:
- имя_приложения_c
- имя_приложения_d
Списки должны быть уникальными. Метод index найдет первое совпадение.
Ответ или решение
Для решения вашей задачи в Ansible с использованием динамических переменных внутри цикла with_nested
, вы можете использовать другой подход, который позволит избежать проблем с неопределенными переменными. Ваша текущая структура с with_nested
создает трудности при доступе к item
внутри блока, поэтому рекомендуется использовать with_subelements
.
Вот исправленный пример вашего файла run.yml
, который выводит желаемый результат:
---
- hosts: localhost
tasks:
- name: Импорт конфигурации
include_vars:
file: ./config.yml
- name: DEBUG
debug:
msg: "{{ item.0.team_name }}: {{ item.1.name }}: {{ index1 | int + 1 }}"
with_subelements:
- "{{ teams }}"
- applications
vars:
team_names: "{{ teams | map(attribute='team_name') | list }}"
index0: "{{ team_names.index(item.0.team_name) }}"
applications: "{{ teams | map(attribute='applications') | list }}"
application_names: "{{ applications[index0 | int] | map(attribute='name') | list }}"
index1: "{{ application_names.index(item.1.name) }}"
Объяснение:
- with_subelements: Этот метод позволяет вам итерироваться по элементам из вложенного списка, что в вашем случае — это
applications
для каждой команды. - Индексация: Мы используем переменные
index0
иindex1
для получения индексов команды и приложения соответственно. Это достигается с помощью методаindex
, который возвращает позицию первого найденного элемента в списке. - Форматирование вывода: Сообщение, которое вы хотите вывести, формируется с помощью f-string, что упрощает отображение имен команды и приложения с их индексами.
Вывод:
Этот подход гарантирует, что вы получите следующий вывод, который вы ожидаете:
msg: 'Name-of-Team_A: app_name_a: 1'
msg: 'Name-of-Team_A: app_name_b: 2'
msg: 'Name-of-Team_B: app_name_c: 1'
msg: 'Name-of-Team_B: app_name_d: 2'
Альтернативный подход:
Если хотите улучшить структуру данных, рассмотрите возможность использования словаря вместо списка. Например, вы можете изменить вашу конфигурацию в config.yml
на следующий формат:
teams:
Name-of-Team_A:
- app_name_a
- app_name_b
Name-of-Team_B:
- app_name_c
- app_name_d
Тогда ваш run.yml
будет выглядеть так:
---
- hosts: localhost
tasks:
- name: Импорт конфигурации
include_vars:
file: ./config.yml
- name: DEBUG
debug:
msg: "{{ item.0.key }}: {{ item.1 }}: {{ teams[item.0.key].index(item.1) + 1 }}"
with_subelements:
- "{{ teams | dict2items }}"
- value
Этот подход более эффективен для манипуляций с уникальными элементами и упрощает понимание структуры данных.
Таким образом, вам удалось эффективно использовать Ansible для динамического извлечения информации из вложенных структур данных.