Ansible中如何遍历嵌套字典并保留键

93次阅读
没有评论

问题描述

在使用Ansible时遇到了一个问题,他无法循环遍历字典中的列表,并保留原始字典的键。以下是他的数据示例:

vars:
  nginx_users:
    'instance1':
      roles:
        - product
        - nginx_instance
      cert_source: internal-ca
      URL: page-nginx.domain.internal
      port: 8090
      downtime: true
      basic_auth:
        - username1
        - username2
      ip_restriction:
        - '0.0.0.0/0'
    'instance2':
      roles:
        - product
        - nginx_instance
      cert_source: internal-ca
      URL: page2-nginx.domain.internal
      port: 8091
      downtime: true
      basic_auth:
        - username1
        - username2
      ip_restriction:
        - '0.0.0.0/0'
    'instance3':
      roles:
        - product
        - nginx_instance

他希望以以下方式循环遍历:

"msg": [
  "instance1",
  [
    "username1"
  ],
  "instance1",
  [
    "username2"
  ],
  "instance2",
  [
    "username1"
  ],
  "instance2",
  [
    "username2"
  ]
  ...
]

他尝试使用以下代码:

...loop: "{{ nginx_users | dict2items }}"when: item.value.basic_auth is defined...

但是他不知道如何循环遍历这些”items”以获取每次迭代的用户列表并保留键。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

我们可以通过简化第一个任务中的字典,并在第二个任务中循环遍历子元素来解决这个问题。以下是任务的代码:

- set_fact:
    nginx_users_selected: "{{ nginx_users_selected|
                              default({})|
                              combine({item.key: item.value}) }}" 
  loop: "{{ nginx_users|
            dict2items|
            json_query('[*].{key: key, value: value.basic_auth}') }}"
  when: item.value
- debug:
    msg: "{{ item.0.key }} {{ item.1 }}"
  loop: "{{ nginx_users_selected|
            dict2items|
            subelements('value') }}"

这将输出:

"msg": "instance2 username1"
"msg": "instance2 username2"
"msg": "instance1 username1"
"msg": "instance1 username2"

然后,我们可以创建所需的结构:

- set_fact:
    my_list: "{{ my_list|default([]) +
                 [ item.0.key, [ item.1 ]] }}"
  loop: "{{ nginx_users_selected|
            dict2items|
            subelements('value') }}"
- debug:
    var: my_list

这将输出:

"my_list": [
  "instance2",
  [
    "username1"
  ],
  "instance2",
  [
    "username2"
  ],
  "instance1",
  [
    "username1"
  ],
  "instance1",
  [
    "username2"
  ]
]

方案2

另一种方法是使用include_tasks和内外循环来解决这个问题。以下是一个示例:

- include_tasks: loop_users.yml
  loop: "{{ nginx_users | dict2items }}"
  when: item.value.basic_auth is defined

loop_users.yml文件中,我们可以使用内外循环来实现所需的结果:

- debug:
    msg: "{{ item.0.key }} {{ item.1 }}"
  loop: "{{ item.value.basic_auth }}"
  loop_control:
    loop_var: inner_item
  vars:
    outer_item: "{{ item }}"

这将输出与方案1相同的结果。

希望这些解决方案对您有所帮助。如果您有任何其他问题,请随时提问。

正文完