如何在 Ansible 中遍历深度为 3 的字典元素列表
How to loop over a list of dict elements deep 3 in Ansible
我的 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_dict
和 with_nested
,但没有任何帮助。
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '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 上搞砸了很多(我认为 I actually recognize those variable names and overall task layout)
Nexus 存储库 POST /v1/repositories/pypi/[hosted|proxy|group]
API 端点期待对您在 data
中的每个存储库调用一次。要实现您的要求,您需要遍历 repo_type
中的键到 select 适当的端点,然后再次遍历 data
中的每个元素以发送 repo 定义以创建。
这实际上可以在您的循环中组合 dict2items
和 subelements
过滤器,如下面的剧本(未直接测试)。
改造的基本情况如下:
- 使用
dict2items
将您的字典转换为 key/value 列表,例如(缩短示例)
- key: hosted
value:
data:
- <repo definition 1>
- <repo definition 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
过滤器的回购定义的显式 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') }}"
我的 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_dict
和 with_nested
,但没有任何帮助。
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '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 上搞砸了很多(我认为 I actually recognize those variable names and overall task layout)
Nexus 存储库 POST /v1/repositories/pypi/[hosted|proxy|group]
API 端点期待对您在 data
中的每个存储库调用一次。要实现您的要求,您需要遍历 repo_type
中的键到 select 适当的端点,然后再次遍历 data
中的每个元素以发送 repo 定义以创建。
这实际上可以在您的循环中组合 dict2items
和 subelements
过滤器,如下面的剧本(未直接测试)。
改造的基本情况如下:
- 使用
dict2items
将您的字典转换为 key/value 列表,例如(缩短示例)- key: hosted value: data: - <repo definition 1> - <repo definition 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
过滤器的回购定义的显式 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') }}"