Ansible根据属性合并两个列表

时间:2019-04-24 14:04:18

标签: ansible

我在剧本中扮演一个角色,该角色使用set_fact生成两个列表。 这两个事实用于不同的任务。 然后,我需要将它们合并以完成最终任务。

list1:
  - name: alice
    roles: ['role1', 'role2']
  - name: bob
    roles: ['role1']

list2:
  - name: alice
    roles: ['role3']
  - name: charlie
    roles: ['role2']

对于我的最后一项任务,我需要输出为:

list3:
  - name: alice
    roles: ['role1', 'role2', 'role3']
  - name: bob
    roles: ['role1']
  - name: charlie
    roles: ['role2']

2 个答案:

答案 0 :(得分:0)

这是一个简单的解决方案。如果由于数据结构的增长而失去控制,则应考虑编写自己的过滤器(example

---
- name: demo playbook for deeps dictionary merge
  hosts: localhost
  gather_facts: false

  vars:
    list1:
      - name: alice
        roles: ['role1', 'role2']
      - name: bob
        roles: ['role1']

    list2:
      - name: alice
        roles: ['role3']
      - name: charlie
        roles: ['role2']

  tasks:

    - debug:
        msg: >-
          roles for {{ item }}:
          {{
            (list1 | json_query("[?name == '" + item +"'].roles")).0 | default([])
            +
            (list2 | json_query("[?name == '" + item +"'].roles")).0 | default([])
          }}
      loop: >-
        {{
          (
            list1 | json_query("[].name")
            +
            list2 | json_query("[].name")
          )
          | unique
        }}

哪个给:

PLAY [demo playbook for deeps dictionary merge] ************************************************************************************************************************************************************************************************************************

TASK [debug] ************************************************************************************************************************************************************************************************************************************************************
Wednesday 24 April 2019  16:23:07 +0200 (0:00:00.046)       0:00:00.046 ******* 
ok: [localhost] => (item=alice) => {
    "msg": "roles for alice: ['role1', 'role2', 'role3']"
}
ok: [localhost] => (item=bob) => {
    "msg": "roles for bob: ['role1']"
}
ok: [localhost] => (item=charlie) => {
    "msg": "roles for charlie: ['role2']"
}

答案 1 :(得分:0)

我在评论中询问了列表和词典,因为它会对解决方案产生影响。如果您要像这样重组数据:

dict1:
  alice: ['role1', 'role2']
  bob: ['role1']

dict2:
  alice: ['role3']
  charlie: ['role2']

然后您的解决方案将变为:

- set_fact:
    dict3: >-
      {{
      dict3|default([])|combine({
      item: (dict1[item]|default([]) + dict2[item]|default([]))|unique
      })
      }}
  loop: "{{ (dict1.keys()|list + dict2.keys()|list)|unique }}"

- debug:
    var: dict3

哪个输出:

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
    "dict3": {
        "alice": [
            "role1", 
            "role2", 
            "role3"
        ], 
        "bob": [
            "role1"
        ], 
        "charlie": [
            "role2"
        ]
    }
}

如果您坚持使用列表,我们可以改进Zeitounator建议的json_query解决方案:

- set_fact:
    list3: >-
      {{
      list3|default([]) + [{
      'name': item,
      'roles': (list1|json_query('[?name==`' + item + '`].roles[]') + list2|json_query('[?name==`' + item + '`].roles[]'))|unique
      }]
      }}
  loop: "{{ (list1|json_query('[].name') + list2|json_query('[].name'))|unique }}"

- debug:
    var: list3

这将产生您想要的输出:

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
    "list3": [
        {
            "name": "alice", 
            "roles": [
                "role1", 
                "role2", 
                "role3"
            ]
        }, 
        {
            "name": "bob", 
            "roles": [
                "role1"
            ]
        }, 
        {
            "name": "charlie", 
            "roles": [
                "role2"
            ]
        }
    ]
}
相关问题