Ansible:按属性过滤列表
我在Ansible中注册了名为“network”的variables:
{ "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" } ] } }
是否有可能得到types=“浮动”的IP地址(“addr”)做这样的事情?
- debug: var={{ network.addresses.private_man | filter type="fixed" | get "addr" }}
我知道语法是错误的,但你明白了。
我已经提交了一个pull请求 (在Ansible 2.2+中提供),通过在Ansible上添加jmespath查询支持,可以使这种情况更容易。 在你的情况下,它会像这样工作:
- debug: msg="{{ addresses | json_query(\"private_man[?type=='fixed'].addr\") }}"
会返回:
ok: [localhost] => { "msg": [ "172.16.1.100" ] }
要过滤一个字典列表,您可以使用selectattrfilter和equaltofilter :
network.addresses.private_man | selectattr("type", "equalto", "fixed")
虽然这理论上应该工作,而且实际上对大多数人来说,它从来没有为我做过。 我曾经使用过的任何Ansible版本(高达2.1)都不知道equalto
filter。 我从来没有想过为什么,但得到了一个解决scheme:Ansible也有filtermatch
和search
,这需要正则expression式:
match
将需要在string中完全匹配,而search
将需要在string内进行匹配。
network.addresses.private_man | selectattr("type", "match", "^fixed$")
为了将字典列表减less到string列表,所以你只能得到一个addr
字段列表,你可以使用mapfilter :
... | map(attribute='addr') | list
或者,如果你想要一个逗号分隔的string:
... | map(attribute='addr') | join(',')
结合起来,看起来像这样。
- debug: msg={{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | join(',') }}
不一定更好,但是因为在这里有很多选项可以使用Jinja语句来完成:
- 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 %}"
哪个返回:
ok: [localhost] => { "msg": "172.16.1.100" }