Ansible: фильтровать список по его атрибутам
У меня есть переменная с именем "network", зарегистрированная в 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"
}
]
}
}
Можно ли получить IP-адрес ( "addr" ) с типом = "плавающий", выполнив что-то вроде этого?
- debug: var={{ network.addresses.private_man | filter type="fixed" | get "addr" }}
Я знаю, что синтаксис неправильный, но вы получаете идею.
Ответы
Ответ 1
Я отправил запрос (доступен в Ansible 2.2+), который упростит эти ситуации, добавив jmespath поддержка запросов на Ansible. В вашем случае это будет работать следующим образом:
- debug: msg="{{ addresses | json_query(\"private_man[?type=='fixed'].addr\") }}"
вернется:
ok: [localhost] => {
"msg": [
"172.16.1.100"
]
}
Ответ 2
Чтобы отфильтровать список диктовок, вы можете использовать фильтр selectattr вместе с тестом equalto:
network.addresses.private_man | selectattr("type", "equalto", "fixed")
Выше требуется Jinja2 v2.8 или новее (независимо от версии Ansible).
Ansible также имеет тесты match
и search
, которые принимают регулярные выражения:
match
потребуется полное совпадение в строке, тогда как для search
потребуется совпадение внутри строки.
network.addresses.private_man | selectattr("type", "match", "^fixed$")
Чтобы свести список dicts к списку строк, чтобы вы получили только список полей addr
, вы можете использовать фильтр карты:
... | map(attribute='addr') | list
Или, если вы хотите строку через запятую:
... | map(attribute='addr') | join(',')
В совокупности это будет выглядеть так.
- debug: msg={{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | join(',') }}
Ответ 3
Не обязательно лучше, но поскольку здесь хорошо иметь параметры, как это сделать, используя Jinja statements:
- debug:
msg: "{% for address in network.addresses.private_man %}\
{% if address.type == 'fixed' %}\
{{ address.addr }}\
{% endif %}\
{% endfor %}"
Или, если вы хотите разместить все в одной строке:
- debug:
msg: "{% for address in network.addresses.private_man if address.type == 'fixed' %}{{ address.addr }}{% endfor %}"
Что возвращает:
ok: [localhost] => {
"msg": "172.16.1.100"
}
Ответ 4
ищите помощи здесь, как бы выглядел фильтр jinja2, если бы я хотел сравнить 2 атрибута списка? пример: я хочу отфильтровать только записи, где host = dnsname
список_серверов: - {хост: сервер1, dnsname: server1.acme.com} - {хост: сервер2, dnsname: server2.acme.com} - {хост: сервер2, dnsname: сервер3}
Ответ 5
Как бы я передать переменную для фильтра?
отладка: msg = {{network.addresses.private_man | selectattr("type", "equalto", {{ x }}) }} selectattr ("type", "equalto", {{x}})}}
не работает