#merge #ansible #ansible-2.x
Вопрос:
Ансибль v2.9.25
Я пытаюсь объединить две структуры данных с помощью Ansible. Я почти на месте, но не могу объединить все данные.
Позвольте мне объяснить:
Я хочу объединить функции main_roles вместе с функциями default_roles:
main_roles:
- name: admin
role_ref: admin
subjects:
- name: test
kind: ServiceAccount
- name: test2
kind: ServiceAccount
- name: edit
role_ref: edit
subjects:
- name: test
kind: ServiceAccount
default_roles:
- name: edit
role_ref: edit
subjects:
- name: merge_me
kind: ServiceAccount
Я успешно совмещаю со следующей задачей:
- name: "Setting var roles_managed"
set_fact:
roles_managed: "{{ roles_managed | default([]) [ item | combine(default_roles|selectattr('name', 'match', item.name) |list)] }}"
loop: "{{ main_roles }}"
Печать var через цикл.
- name: "print all roles"
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ roles_managed }}"
ok: [] => (item={u'subjects': [{u'kind': u'ServiceAccount', u'name': u'test'}, {u'kind': u'ServiceAccount', u'name': u'test2'}], u'name': u'admin', u'role_ref': u'admin'}) => {
"msg": {
"name": "admin",
"role_ref": "admin",
"subjects": [
{
"kind": "ServiceAccount",
"name": "test"
},
{
"kind": "ServiceAccount",
"name": "test2"
}
]
}
}
ok: [] => (item={u'subjects': [{u'kind': u'ServiceAccount', u'name': u'merge_me'}], u'name': u'edit', u'role_ref': u'edit'}) => {
"msg": {
"name": "edit",
"role_ref": "edit",
"subjects": [
{
"kind": "ServiceAccount",
"name": "merge_me"
}
]
}
}
Это приводит к объединению на item.name
. Но я хочу, чтобы результатом было также слияние предметов. Поэтому мне понадобится конечный результат merge_me
и test
( subjects
ниже name:edit
):
- name: edit
role_ref: edit
subjects:
- name: merge_me
kind: ServiceAccount
- name: test
kind: ServiceAccount
То, что я понимаю под Ansible, по умолчанию не является рекурсивным слиянием. Поэтому мне нужно было бы установить recursive=true
combine
фильтр. См.: Объединение хэшей/словарей
Но я не могу успешно установить это в своем контексте.
Когда я пытаюсь: {{ roles_managed | default([]) [ item | combine(default_role_bindings, recursive=true|selectattr('name', 'match', item.name) |list)] }}
например, я получаю 'bool' object is not iterable"
код ошибки…
Я перепробовал множество вариантов и просмотрел множество других постов. Но я все еще безуспешно, наверное, после слишком многих часов ;). Надеюсь, у кого-то есть решение!
Ответ №1:
Как main_roles, так и default_roles являются списками. Невозможно объединить списки. Вместо этого их можно добавлять и группировать по имени. Затем объедините словари с одинаковым названием, например
- set_fact:
my_roles: "{{ my_roles|d([]) [item.1|combine(list_merge='append')] }}"
loop: "{{ (main_roles default_roles)|groupby('name') }}"
дает
my_roles:
- name: admin
role_ref: admin
subjects:
- kind: ServiceAccount
name: test
- kind: ServiceAccount
name: test2
- name: edit
role_ref: edit
subjects:
- kind: ServiceAccount
name: test
- kind: ServiceAccount
name: merge_me
Используйте list_merge=’добавить’, доступный с 2.10, для добавления элементов списков.
Добавьте темы самостоятельно, если опция добавить недоступна в вашей версии, например, задача ниже дает тот же результат
- set_fact:
my_roles: "{{ my_roles|d([]) [item.1.0|combine({'subjects':_subj})] }}"
loop: "{{ (main_roles default_roles)|groupby('name') }}"
vars:
_subj: "{{ item.1|map(attribute='subjects')|flatten }}"
Комментарии:
1. Спасибо за ваш пример! Я получаю
{"msg": "'recursive' is the only valid keyword argument"}
оценку в своем окружении. Похожеlist_merge=
, это анзибельная штука 2.10 ? (на данный момент мне 2,9)2. Видите ли вы какое-либо решение до 2.10? Я работаю над RHEL, и Ansible 2.10 на данный момент не поддерживается: access.redhat.com/articles/5392421
3. ДА. Я обновил ответ.
4. Действительно потрясающе! Спасибо за решение 2.9 и 2.10, сегодня я многое узнал о манипулировании данными и Ансибле.