Объединение двух структур данных с помощью Ansible

#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, сегодня я многое узнал о манипулировании данными и Ансибле.