Ansible: filtruj listę według jej atrybutów

84

Mam zmienną o nazwie „sieć” zarejestrowaną w 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"
            }
        ]
    }
}

Czy można uzyskać adres IP („addr”) z type = „floating”, robiąc coś takiego?

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

Wiem, że składnia jest nieprawidłowa, ale masz pomysł.

Guido
źródło

Odpowiedzi:

41

Mam złożyła wniosek ciągnącego (dostępny w ansibl 2.2+) jest, że będzie to rodzaju sytuacjach łatwiej dodając jmespath obsługę zapytań o ansibl. W twoim przypadku działałoby to tak:

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

zwróci:

ok: [localhost] => {
    "msg": [
        "172.16.1.100"
    ]
}
Filipe
źródło
3
Musisz zainstalować „jmespath” przed uruchomieniem filtru json_query.
ceving
Po prostu zrezygnowałem z instalowania jmespath ze względu na różnice w wersjach Pythona. To nie jest tak trywialne rozwiązanie, jak wygląda na Ansible 2.4+
Stuart Watt
1
@StuartWatt możesz potrzebować pyenv, aby oderwać się od wersji pythona systemu operacyjnego. Możesz spróbować pyenv, pyenv virtualenvs lub niektórzy wolą pipenv. Będą działać tak samo.
Jepper
@Jepper Jeśli potrzebujesz zupełnie nowego Pythona do korzystania z Ansible, to przegrana bitwa. (I używałem pyenv i nadal miałem te problemy :-)
Stuart Watt
128

Aby przefiltrować listę dykt, możesz użyć filtra selectattr razem z testem equalto :

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

Powyższe wymaga Jinja2 v2.8 lub nowszej (niezależnie od wersji Ansible).


Ansible mamatchsearch również testy i , które przyjmują wyrażenia regularne:

matchbędzie wymagać pełnego dopasowania w ciągu, podczas gdy searchbędzie wymagało dopasowania wewnątrz ciągu.

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

Aby zredukować listę dykt do listy ciągów, aby uzyskać tylko listę addrpól, możesz użyć filtra mapy :

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

Lub jeśli chcesz ciąg znaków oddzielonych przecinkami:

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

W połączeniu wyglądałoby to tak.

- debug: msg={{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | join(',') }}
udondan
źródło
1
Jeśli chcesz, aby były to lista, a nie ciąg znaków oddzielonych przecinkami, możesz również użyć:{{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | list }}
TrinitronX
1
czy podany przez Ciebie link się zmienił? nie mogę znaleźć „dopasowania” i „wyszukiwania” na tej stronie
activedecay
1
@activedecay Wygląda na to, że zniknął z tej strony, tak. Jedyna wzmianka, jaką mogłem znaleźć, znajduje się na tej stronie: docs.ansible.com/ansible/latest/user_guide/ ... Zaktualizowałem link, dzięki!
udondan
19

Niekoniecznie lepiej, ale ponieważ fajnie jest mieć opcje, oto jak to zrobić za pomocą instrukcji Jinja :

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

Lub jeśli wolisz umieścić to wszystko w jednej linii:

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

Który zwraca:

ok: [localhost] => {
    "msg": "172.16.1.100"
}
bmaupin
źródło