Ansible: filtra una lista in base ai suoi attributi

Ho variabile denominata “rete” registrata 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" } ] } } 

È ansible ottenere l’indirizzo IP (“addr”) con type = “floating” facendo qualcosa di simile?

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

So che la syntax è sbagliata ma ti viene l’idea.

Ho inviato una richiesta pull (disponibile in Ansible 2.2+) che renderà questo tipo di situazioni più semplice aggiungendo il supporto di query jmespath su Ansible. Nel tuo caso funzionerebbe come:

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

ritornerebbe:

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

Per filtrare un elenco di dicts è ansible utilizzare il filtro selectattr insieme al test di equalto :

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

Quanto sopra richiede Jinja2 v2.8 o successivo (indipendentemente dalla versione di Ansible).


Anche Ansible ha i test match e search , che prendono espressioni regolari:

match richiederà una corrispondenza completa nella stringa, mentre la search richiederà una corrispondenza all’interno della stringa.

 network.addresses.private_man | selectattr("type", "match", "^fixed$") 

Per ridurre l’elenco di dit a un elenco di stringhe, in modo da ottenere solo un elenco dei campi addr , puoi utilizzare il filtro della mappa :

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

O se vuoi una stringa separata da virgole:

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

Combinato, sembrerebbe questo.

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

Non necessariamente migliore, ma dal momento che è bello avere opzioni ecco come farlo usando le istruzioni Jinja :

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

O se preferisci mettere tutto su una riga:

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

Che restituisce:

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