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"
}
我在 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, whilesearch
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"
}