使用 Ansible 合并两个数据结构

Merging two data structures with Ansible

Ansible v2.9.25

我正在尝试使用 Ansible 合并两个数据结构。我快到了,但我无法合并所有数据。

让我解释一下:

我想合并 main_rolesdefault_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 }}"

通过循环打印变量。

- 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_metest 的最终结果(name:edit 下的 subjects):

  - name: edit
    role_ref: edit
    subjects:
      - name: merge_me
        kind: ServiceAccount
      - name: test
        kind: ServiceAccount

据我了解,Ansible 默认情况下不会递归合并。所以我需要在 combine 过滤器中设置 recursive=true。参见:Combining hashes/dictionaries

但我无法在我的上下文中成功设置它。

当我尝试时:例如 {{ roles_managed | default([]) + [ item | combine(default_role_bindings, recursive=true|selectattr('name', 'match', item.name) |list)] }} 我得到一个 'bool' object is not iterable" 错误代码...

我尝试了很多变体并搜索了许多其他帖子。但是在可能太多小时之后我仍然没有成功;)。希望有人有解决方案!

main_rolesdefault_roles都是列表。无法合并列表。相反,可以添加它们和 groupby 名称。然后合并同名的字典,例如

    - 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

使用从 2.10 开始可用的 list_merge='append' 来附加列表的项目。


如果 append 选项在您的版本中不可用,请自行添加 subjects,例如下面的任务给出了相同的结果

    - 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 }}"