Ansible:按属性过滤列表

Ansible: filter a list by its attributes

我在 Ansible 中注册了名为 "network" 的变量:

{
    "addresses": {
        "private_ext": [
            {
                "type": "fixed",
                "addr": "172.16.2.100"
            }
        ],
        "private_man": [
            {
                "type": "fixed",
                "addr": "172.16.1.100"
            },
            {
                "type": "floating",
                "addr": "10.90.80.10"
            }
        ]
    }
}

是否可以通过 type="floating" 获取 IP 地址 ("addr")?

- debug: var={{ network.addresses.private_man | filter type="fixed" | get "addr" }}

我知道语法有误,但你明白了。

要过滤字典列表,您可以使用 selectattr filter together with the equalto test:

network.addresses.private_man | selectattr("type", "equalto", "fixed")

以上需要Jinja2 v2.8或更高版本(不考虑Ansible版本)。


Ansible 也 has the tests match and search,采用正则表达式:

match will require a complete match in the string, while search will require a match inside of the string.

network.addresses.private_man | selectattr("type", "match", "^fixed$")

要将字典列表缩减为字符串列表,这样您只能得到 addr 字段的列表,您可以使用 map filter:

... | map(attribute='addr') | list

或者如果你想要一个逗号分隔的字符串:

... | map(attribute='addr') | join(',')

结合起来,它看起来像这样。

- debug: msg={{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | join(',') }}

我已经在 Ansible 上提交了 pull request (available in Ansible 2.2+) that will make this kinds of situations easier by adding jmespath 查询支持。在您的情况下,它的工作方式如下:

- debug: msg="{{ addresses | json_query(\"private_man[?type=='fixed'].addr\") }}"

会 return:

ok: [localhost] => {
    "msg": [
        "172.16.1.100"
    ]
}

不一定更好,但是因为有选项很好所以这里是如何使用 Jinja statements:

- debug:
    msg: "{% for address in network.addresses.private_man %}\
        {% if address.type == 'fixed' %}\
          {{ address.addr }}\
        {% endif %}\
      {% endfor %}"

或者,如果您更喜欢将所有内容放在一行中:

- debug:
    msg: "{% for address in network.addresses.private_man if address.type == 'fixed' %}{{ address.addr }}{% endfor %}"

哪个returns:

ok: [localhost] => {
    "msg": "172.16.1.100"
}