在 Ansible 中按键合并两个字典

在 Ansible 中按键合并两个字典

我正在寻求帮助,以特定方式合并两本词典。如果您能提供任何想法,我将不胜感激。

我有两个这样的词典:第一个词典:

servers:
  server1:
    Property1: A
    Property2: B
    Property3: C
  server2:
    Property1: A
    Property2: B
    Property3: C

第二個錄音:

management:
  server1: ip1_addr
  server2: ip2_addr

期望结果:

servers:
  server1:
    Property1: A
    Property2: B
    Property3: C
    Property4: ip1_addr
  server2:
    Property1: A
    Property2: B
    Property3: C
    Property4: ip2_addr

或者我可能选择了错误的路径,我所需要的只是一次循环两个字典,以获取 server1 键下的 ip1_addr 和 server2 键下的 ip2_addr

答案1

还有更多选择:

  1. 转换字典管理
    - set_fact:
        mgmt: "{{ mgmt|d({})|
                  combine({item.key: {'Property4': item.value}}) }}"
      loop: "{{ management|dict2items }}"

如果您想避免迭代使用:

a) 过滤器社区.general.dict_kv

    mgmt: "{{ dict(management.keys()|
                   zip(management.values()|
                       map('community.general.dict_kv', 'Property4'))) }}"

b) 过滤器社区.general.json_query

    mgmt: "{{ dict(management|dict2items|
                   json_query('[].[key, {Property4: value}]')) }}"

C)金贾

    mgmt_str: |
      {% for k,v in management.items() %}
      {{ k }}:
        Property4: {{ v }}
      {% endfor %}
    mgmt: "{{ mgmt_str|from_yaml }}"

所有选项都会产生相同的结果

  mgmt:
    server1:
      Property4: ip1_addr
    server2:
      Property4: ip2_addr

然后,结合字典

  srvs: "{{ servers|combine(mgmt, recursive=True) }}"

给出了期望的结果

  srvs:
    server1:
      Property1: A
      Property2: B
      Property3: C
      Property4: ip1_addr
    server2:
      Property1: A
      Property2: B
      Property3: C
      Property4: ip2_addr

完整测试剧本的示例

- hosts: localhost

  vars:

    servers:
      server1:
        Property1: A
        Property2: B
        Property3: C
      server2:
        Property1: A
        Property2: B
        Property3: C
        
    management:
      server1: ip1_addr
      server2: ip2_addr

    mgmt: "{{ dict(management.keys()|
                   zip(management.values()|
                       map('community.general.dict_kv', 'Property4'))) }}"
    srvs: "{{ servers|combine(mgmt, recursive=True) }}"

  tasks:

    - debug:
        var: mgmt
    - debug:
        var: srvs

  1. 使用 Jinja 创建 YAML 结构并使用过滤器进行转换来自_yaml. 声明服务端下面给出了相同的结果
    srvs_str: |
      {% for k,v in servers.items() %}
      {{ k }}:
         {{ v|combine({'Property4': management[k]}) }}
      {% endfor %}
    srvs: "{{ srvs_str|from_yaml }}"

  1. 如果要迭代结果,将两个字典都转换为列表会更容易
    - set_fact:
        mgmt_list: "{{ mgmt_list|d([]) +
                       [{'server': item.key, 'Property4': item.value}] }}"
      loop: "{{ management|dict2items }}"

    - set_fact:
        srvs_list: "{{ srvs_list|d([]) +
                       [{'server': item.key}|combine(item.value)] }}"
      loop: "{{ servers|dict2items }}"

如果你想避免迭代使用json_查询

    mgmt_list: "{{ management|dict2items(key_name='server',
                                         value_name='Property4') }}"
    srvs_list: "{{ servers|dict2items|
                   json_query('[].merge({server: key}, value)') }}"

  mgmt_list:
  - Property4: ip1_addr
    server: server1
  - Property4: ip2_addr
    server: server2

  srvs_list:
  - Property1: A
    Property2: B
    Property3: C
    server: server1
  - Property1: A
    Property2: B
    Property3: C
    server: server2

然后使用社区.一般筛选社区.general.lists_mergeby

  srvs: "{{ srvs_list|community.general.lists_mergeby(mgmt_list, 'server') }}"

给出一个列表,而不是预期的字典

  srvs:
  - Property1: A
    Property2: B
    Property3: C
    Property4: ip1_addr
    server: server1
  - Property1: A
    Property2: B
    Property3: C
    Property4: ip2_addr
    server: server2

您可以将列表转换为字典

  srvs_dict: "{{ dict(srvs|map(attribute='server')|zip(srvs)) }}"

, 或者

  srvs_dict: "{{ dict(srvs|json_query('[].[server, @]')) }}"

两种选择的结果相同

  srvs_dict:
    server1:
      Property1: A
      Property2: B
      Property3: C
      Property4: ip1_addr
      server: server1
    server2:
      Property1: A
      Property2: B
      Property3: C
      Property4: ip2_addr
      server: server2

完整测试剧本的示例

- hosts: localhost

  vars:

    servers:
      server1:
        Property1: A
        Property2: B
        Property3: C
      server2:
        Property1: A
        Property2: B
        Property3: C
        
    management:
      server1: ip1_addr
      server2: ip2_addr

    mgmt_list: "{{ management|dict2items(key_name='server',
                                         value_name='Property4') }}"
    srvs_list: "{{ servers|dict2items|
                   json_query('[].merge({server: key}, value)') }}"
    srvs: "{{ srvs_list|community.general.lists_mergeby(mgmt_list, 'server') }}"
    
  tasks:

    - debug:
        var: mgmt_list
    - debug:
        var: srvs_list
    - debug:
        var: srvs

相关内容