如何遍历Ansible中深度为3的字典元素列表



我的var文件中有以下变量:

repo_type:
hosted:
data:
- name: hosted_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: hosted_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once
proxy:
data:
- name: proxy_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: proxy_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once
group:
data:
- name: group_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: group_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once

我想配置一个任务来循环(托管,代理和组)和主体在数据字典。

任务如下:

- name: Create pypi hosted Repos
uri:
url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}
{{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/repositories/pypi/{{ item.key}}"
user: "{{ nexus_api_user }}"
password: "{{ nexus_default_admin_password }}"
headers:
accept: "application/json"
Content-Type: "application/json"
body_format: json
method: POST
force_basic_auth: yes
validate_certs: "{{ nexus_api_validate_certs }}"
body: "{{  item  }}"
status_code: 201
no_log: no
with_dict: "{{ repo_type}}"

我试过with_items,with_dictwith_nested,但没有任何帮助。

任务包含一个未定义变量的选项。此错误是:'dict object'没有属性'data'

任何帮助将不胜感激!

如果您的目标是将data键的内容作为一个平面列表循环遍历,那么您可以这样做:

- debug:
msg: "repo {{ item.name }} write_policy {{ item.storage.write_policy }}"
loop_control:
label: "{{ item.name }}"
loop: "{{ repo_type | json_query('*.data[]') }}"

使用JMESPath表达式从中获取data键顶级字典,然后将结果嵌套列表平面化。在换句话说,它将原始结构转换为:

- name: hosted_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: hosted_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: proxy_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: proxy_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: group_repo1
online: true
storage:
blobstarage: default
write_policy: allow_once
- name: group_repo2
online: true
storage:
blobstarage: default
write_policy: allow_once

使用示例数据运行时,将产生如下输出:

TASK [debug] *********************************************************************************************************
ok: [localhost] => (item=hosted_repo1) => {
"msg": "repo hosted_repo1 write_policy allow_once"
}
ok: [localhost] => (item=hosted_repo2) => {
"msg": "repo hosted_repo2 write_policy allow_once"
}
ok: [localhost] => (item=proxy_repo1) => {
"msg": "repo proxy_repo1 write_policy allow_once"
}
ok: [localhost] => (item=proxy_repo2) => {
"msg": "repo proxy_repo2 write_policy allow_once"
}
ok: [localhost] => (item=group_repo1) => {
"msg": "repo group_repo1 write_policy allow_once"
}
ok: [localhost] => (item=group_repo2) => {
"msg": "repo group_repo2 write_policy allow_once"
}

如果你想做其他事情,请更新你的问题它清楚地显示了您期望的值循环。

正如@larsk所报道的,你实际上没有设法解释清楚你是如何试图循环你的数据和你的api调用实际上是什么。

但是这次你很幸运,因为我在Nexus上搞砸了很多(我想我实际上认识那些变量名和整体任务布局)

Nexus RepositoryPOST /v1/repositories/pypi/[hosted|proxy|group]API端点期望对data中的每个repos进行一次调用。要实现您的需求,您需要遍历repo_type中的键以选择适当的端点,然后再次遍历data中的每个元素以发送要创建的repo定义。

这实际上是可以在你的循环中结合dict2itemssubelements过滤器,就像下面的剧本(没有直接测试)。

转换的基础如下:

  1. 使用dict2items将您的字典转换为键/值列表,例如(缩短示例)
    - key: hosted
    value:
    data:
    - <repo definition 1>
    - <repo definition 2>
    [...]
    
  2. 使用subelements过滤器将每个顶部元素与value.data中的每个元素组合在一起,例如:
    - # <- This is the entry for first repo i.e. `item` in your loop
    - key: hosted # <- this is the start of the corresponding top element i.e. `item.0` in your loop
    value:
    data:
    - <repo definition 1>
    - <repo definition 2>
    - <repo definition 1> # <- this is the sub-element i.e. `item.1` in your loop 
    - # <- this is the entry for second repo
    - key: hosted
    value:
    data:
    - <repo definition 1>
    - <repo definition 2>
    - <repo definition 2>
    [...]
    

根据您的评论和我的经验,我使用to_json过滤器在我的示例中添加了repo定义的显式json序列化。

把这些放在一起就得到:

- name: Create pypi hosted Repos
uri:
url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}
{{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/repositories/pypi/{{ item.0.key }}"
user: "{{ nexus_api_user }}"
password: "{{ nexus_default_admin_password }}"
headers:
accept: "application/json"
Content-Type: "application/json"
body_format: json
method: POST
force_basic_auth: yes
validate_certs: "{{ nexus_api_validate_certs }}"
body: "{{ item.1 | to_json }}"
status_code: 201
no_log: no
loop: "{{ repo_type | dict2items | subelements('value.data') }}"