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)都不知道equaltofilter。 我从来没有想过为什么,但得到了一个解决scheme:Ansible也有filtermatchsearch ,这需要正则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" }