Ansible: filter a list by its attributes

匿名 (未验证) 提交于 2019-12-03 01:39:01

问题:

I have variable named "network" registered in Ansible:

{     "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"             }         ]     } } 

Is it possible to get the IP address ("addr") with type="floating" doing something like this?

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

I know the syntax is wrong but you get the idea.

回答1:

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"     ] } 


回答2:

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 match 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(',') }} 


回答3:

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" } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!