Ansible: bir listeyi özniteliklerine göre filtreleyin


84

Ansible'da kayıtlı "ağ" adlı değişkenim var:

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

IP adresini ("addr") type = "kayan" ile bunun gibi bir şey yapmak mümkün müdür?

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

Sözdiziminin yanlış olduğunu biliyorum ama anladınız.

Yanıtlar:


41

Ansible'a jmespath sorgu desteği ekleyerek bu tür durumları kolaylaştıracak bir çekme isteği gönderdim (Ansible 2.2+ sürümünde mevcuttur). Sizin durumunuzda şu şekilde çalışır:

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

şunu döndürür:

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

3
Json_query filtresini çalıştırmadan önce "jmespath" kurmanız gerekir.
2017

Ve Python sürüm farklılıkları nedeniyle jmespath'i kurmaya çalışmaktan vazgeçtim. Ansible 2.4+ 'de göründüğü kadar önemsiz bir çözüm değil
Stuart Watt

1
@StuartWatt kendinizi işletim sistemi python sürümünden soyutlamak için pyenv'e ihtiyacınız olabilir. Pyenv, pyenv virtualenv'leri deneyebilirsiniz veya bazı insanlar pipenv'i tercih eder. Hepsi aynı şekilde çalışacaklar.
Jepper

@Jepper Ansible'ı kullanmak için yepyeni bir Python'a ihtiyacınız varsa, bu kaybedilen bir savaş. (Ve pyenv kullanıyordum ve hala bu sorunları yaşıyordum :-)
Stuart Watt

128

Bir dicts listesini filtrelemek için, selectattr filtresini equto test ile birlikte kullanabilirsiniz :

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

Yukarıdakiler Jinja2 v2.8 veya üzerini gerektirir (Ansible sürümünden bağımsız olarak).


Ansible ayrıca testlere sahiptir matchvesearch düzenli ifadeler alır:

matchdizede tam bir eşleşme searchgerektirirken, dizenin içinde bir eşleşme gerektirir.

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

Diktlerin listesini dizeler listesine indirgemek, böylece yalnızca addralanların bir listesini elde etmek için harita filtresini kullanabilirsiniz :

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

Veya virgülle ayrılmış bir dize istiyorsanız:

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

Kombine olsaydı şöyle görünürdü.

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

1
Bunun yerine virgülle ayrılmış dize daha liste halinde isterseniz de kullanabilirsiniz:{{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | list }}
TrinitronX

1
Sağladığınız bağlantı değişti mi? o sayfada "eşleşme" ve "arama" bulamıyorum
aktive edildiAralık

1
@activedecay O sayfadan gitmiş gibi görünüyor, evet. Şu anda bulabildiğim tek şey bu sayfada: docs.ansible.com/ansible/latest/user_guide/… Bağlantıyı güncelledim, teşekkürler!
udondan

19

Mutlaka daha iyi değil, ancak seçeneklere sahip olmak güzel olduğu için Jinja ifadelerini kullanarak bunu nasıl yapacağınız aşağıda açıklanmıştır :

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

Veya hepsini tek bir satıra koymayı tercih ederseniz:

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

Hangi döndürür:

ok: [localhost] => {
    "msg": "172.16.1.100"
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.