是否可以使用Ansible/Jinja2压缩列表列表?

Tom*_*Tom 19 jinja2 ansible ansible-playbook

我的基本问题是,在创建一组aws服务器时,我想配置它们以了解彼此.

创建每个服务器后,它们的详细信息将保存在已注册的"服务器"var中(如下所示).我真正希望在创建之后能够执行的任务是这样的:

- 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
Run Code Online (Sandbox Code Playgroud)

将列表提供两次到'with_nested'是必不可少的.

获取列表清单很容易:

"{{ servers.results | map(attribute='tagged_instances') | list }}"
Run Code Online (Sandbox Code Playgroud)

返回:

[ 
  [ { "private_ip": "ip1", "public_dns_name": "dns1" } , { ... }],
  [ { ... }, { ... } ]
]
Run Code Online (Sandbox Code Playgroud)

但你怎么会把它变成:

[
  { "private_ip": "ip1", "public_dns_name": "dns1" },
  { ... },
  { ... }, 
  { ... }
]
Run Code Online (Sandbox Code Playgroud)

'servers'注册的var看起来像:

"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",
                    ...
                }
            ]
        },
        ...
    ]
}
Run Code Online (Sandbox Code Playgroud)

注意:我有一个非常丑陋的解决方案,使用'with_flattened'和一个调试语句来创建一个新注册的var'blattened_servers'然后我再次映射.但我希望有一个更优雅的解决方案:)

小智 50

Jinja2带有一个内置过滤器sum,可以像下面这样使用:

{{ servers.results | sum(attribute='tagged_instances', start=[]) }}
Run Code Online (Sandbox Code Playgroud)

  • 这也适用于一系列数组!我的数据看起来像`[[1,2],[3,4]]`并使用`| sum(start = [])`将它展平为`[1,2,3,4]`.非常感谢 - 从来没有想过这个. (6认同)
  • 如果需要获取所有实例ID,可以像上面这样扩展上面的示例:`code` - set_fact:instance_ids ="{{servers.results | sum(attribute ='tagged_instances',start = [])| map(属性) ='id')| list}}" (3认同)
  • 我发现这是最"回答"的答案,而且效果很好. (3认同)

Ale*_*lex 8

有点晚了,但从 ansible 2.5 开始,您可以这样做:

 "{{ servers.results | map(attribute='tagged_instances') | list | flatten }}"
Run Code Online (Sandbox Code Playgroud)

  • 干净多了,谢谢!我发现`| flatten` 甚至可以在没有 `| 的生成器上工作 列表` (2认同)

Vor*_*Vor 2

您可以进行列表理解,将其转换为字典列表。

例如:

- name: Convert
  shell: python -c "print [x for b in {{ servers }}['servers']['results'] for x in b['tagged_instances']]"
  register: my_list_of_dicts
Run Code Online (Sandbox Code Playgroud)

假设该{{ servers }}变量保存整个字典(不是 json)。