web-dev-qa-db-fra.com

Ansible: filtrer une liste par ses attributs

J'ai une variable nommée "réseau" enregistrée dans 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"
            }
        ]
    }
}

Est-il possible d'obtenir l'adresse IP ("addr") avec type = "floating" faisant quelque chose comme ceci?

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

Je sais que la syntaxe est fausse mais vous voyez l'idée.

65
Guido

J'ai envoyé un demande d'extraction (disponible dans Ansible 2.2+) qui facilitera ce genre de situation en ajoutant jmespath support de requête sur Ansible. Dans votre cas, cela fonctionnerait comme:

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

retournerais:

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

Pour filtrer une liste de dict, vous pouvez utiliser le filtre selectattr avec le equalto test :

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

Ce qui précède nécessite Jinja2 v2.8 ou version ultérieure (quelle que soit la version de Ansible).


Ansible aussi a les tests match et search , qui prennent des expressions régulières:

match nécessitera une correspondance complète dans la chaîne, tandis que search nécessitera une correspondance à l'intérieur de la chaîne.

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

Pour réduire la liste des dessins à une liste de chaînes, afin que vous n'obteniez qu'une liste des champs addr, vous pouvez utiliser le filtre de carte :

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

Ou si vous voulez une chaîne séparée par des virgules:

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

Combiné, cela ressemblerait à ceci.

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

Pas nécessairement mieux, mais comme il est agréable d'avoir des options, voici comment le faire en utilisant déclarations Jinja :

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

Ou si vous préférez mettre tout cela sur une seule ligne:

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

Qui retourne:

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