通过属性过滤列表

我有一个名为“网络”的变量注册在安塞尔:

{
"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 = “ float”的 IP 地址(“ addr”) ?

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

我知道语法有问题,但你明白我的意思。

140164 次浏览

To filter a list of dicts you can use the selectattr filter together with the equalto test:

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

The above requires Jinja2 v2.8 or later (regardless of Ansible version).


Ansible also has the tests ABC0 and search, which take regular expressions:

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$")

To reduce the list of dicts to a list of strings, so you only get a list of the addr fields, you can use the map filter:

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

Or if you want a comma separated string:

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

Combined, it would look like this.

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

I've submitted a pull request (available in Ansible 2.2+) that will make this kinds of situations easier by adding jmespath query support on Ansible. In your case it would work like:

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

would return:

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

Not necessarily better, but since it's nice to have options here's how to do it using Jinja statements:

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

Or if you prefer to put it all on one line:

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

Which returns:

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