是否可以使用 Ansible / Jinja2 展平列表列表?
Is it possible to flatten a lists of lists with Ansible / Jinja2?
我的基本问题是,在创建一组 aws 服务器后,我想将它们配置为相互了解。
创建每个服务器后,它们的详细信息将保存在已注册的 'servers' 变量中(如下所示)。创建后我真正希望能够做的是 运行 像这样的任务:
- name: Add servers details to all other servers
lineinfile:
dest: /path/to/configfile
line: "servername={{ item.1.private_ip }}"
delegate_to: "{{ item.0.public_dns_name }}"
with_nested:
- list_of_servers
- list_of_servers
向 'with_nested' 提供两次列表在这里是必不可少的。
获取列表的列表很容易做到:
"{{ servers.results | map(attribute='tagged_instances') | list }}"
哪个returns:
[
[ { "private_ip": "ip1", "public_dns_name": "dns1" } , { ... }],
[ { ... }, { ... } ]
]
但是你会如何把它变成:
[
{ "private_ip": "ip1", "public_dns_name": "dns1" },
{ ... },
{ ... },
{ ... }
]
'servers' 注册的变量如下所示:
"servers": {
"changed": true,
"msg": "All items completed",
"results": [
{
...
"tagged_instances": [
{
...
"private_ip": "ip1",
"public_dns_name": "dns1",
...
},
{
...
"private_ip": "ip2",
"public_dns_name": "dns2",
...
}
]
},
{
...
"tagged_instances": [
{
...
"private_ip": "ip3",
"public_dns_name": "dn3",
...
},
{
...
"private_ip": "ip4",
"public_dns_name": "dns4",
...
}
]
},
...
]
}
注意:我有一个非常丑陋的解决方案,使用 'with_flattened' 和调试语句创建一个新的注册变量 'flattened_servers' 然后我再次映射。但我希望有一个更优雅的解决方案:)
您可以进行列表推导,将其转换为字典列表。
例如:
- name: Convert
shell: python -c "print [x for b in {{ servers }}['servers']['results'] for x in b['tagged_instances']]"
register: my_list_of_dicts
假设 {{ servers }}
变量包含整个字典(而不是 json)。
只是想列出 "ugly" 解决方法,因为 python 代码对我不起作用
- debug: var=item
with_flattened:
- "{{ servers.results|map(attribute='tagged_instances')|list }}"
register: servers_instances_tmp
no_log: True
- set_fact: servers_instances="{{ servers_instances_tmp.results|map(attribute='item')|list }}"
- debug: var=servers_instances
Jinja2 带有内置过滤器 sum
可以像这样使用:
{{ servers.results | sum(attribute='tagged_instances', start=[]) }}
有点晚了,但是从 ansible 2.5 开始你可以这样做:
"{{ servers.results | map(attribute='tagged_instances') | list | flatten }}"
我的基本问题是,在创建一组 aws 服务器后,我想将它们配置为相互了解。
创建每个服务器后,它们的详细信息将保存在已注册的 'servers' 变量中(如下所示)。创建后我真正希望能够做的是 运行 像这样的任务:
- name: Add servers details to all other servers
lineinfile:
dest: /path/to/configfile
line: "servername={{ item.1.private_ip }}"
delegate_to: "{{ item.0.public_dns_name }}"
with_nested:
- list_of_servers
- list_of_servers
向 'with_nested' 提供两次列表在这里是必不可少的。
获取列表的列表很容易做到:
"{{ servers.results | map(attribute='tagged_instances') | list }}"
哪个returns:
[
[ { "private_ip": "ip1", "public_dns_name": "dns1" } , { ... }],
[ { ... }, { ... } ]
]
但是你会如何把它变成:
[
{ "private_ip": "ip1", "public_dns_name": "dns1" },
{ ... },
{ ... },
{ ... }
]
'servers' 注册的变量如下所示:
"servers": {
"changed": true,
"msg": "All items completed",
"results": [
{
...
"tagged_instances": [
{
...
"private_ip": "ip1",
"public_dns_name": "dns1",
...
},
{
...
"private_ip": "ip2",
"public_dns_name": "dns2",
...
}
]
},
{
...
"tagged_instances": [
{
...
"private_ip": "ip3",
"public_dns_name": "dn3",
...
},
{
...
"private_ip": "ip4",
"public_dns_name": "dns4",
...
}
]
},
...
]
}
注意:我有一个非常丑陋的解决方案,使用 'with_flattened' 和调试语句创建一个新的注册变量 'flattened_servers' 然后我再次映射。但我希望有一个更优雅的解决方案:)
您可以进行列表推导,将其转换为字典列表。
例如:
- name: Convert
shell: python -c "print [x for b in {{ servers }}['servers']['results'] for x in b['tagged_instances']]"
register: my_list_of_dicts
假设 {{ servers }}
变量包含整个字典(而不是 json)。
只是想列出 "ugly" 解决方法,因为 python 代码对我不起作用
- debug: var=item
with_flattened:
- "{{ servers.results|map(attribute='tagged_instances')|list }}"
register: servers_instances_tmp
no_log: True
- set_fact: servers_instances="{{ servers_instances_tmp.results|map(attribute='item')|list }}"
- debug: var=servers_instances
Jinja2 带有内置过滤器 sum
可以像这样使用:
{{ servers.results | sum(attribute='tagged_instances', start=[]) }}
有点晚了,但是从 ansible 2.5 开始你可以这样做:
"{{ servers.results | map(attribute='tagged_instances') | list | flatten }}"