Ansible:按属性过滤列表


83

我在Ansible中注册了一个名为“ network”的变量:

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

是否可以像这样通过type =“ floating”获取IP地址(“ addr”)?

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

我知道语法错误,但是您明白了。

Answers:


41

我已经提交了一个拉取请求(在Ansible 2.2+中可用),通过在Ansible上添加jmespath查询支持,可以简化这种情况。在您的情况下,它将像:

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

会返回:

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

3
您需要在运行json_query过滤器之前安装“ jmespath”。
ceving

由于Python版本的差异,我只是放弃尝试安装jmespath。这不是微不足道的解决方案,因为它看起来Ansible 2.4 +
司徒瓦特

1
@StuartWatt您可能需要pyenv才能使自己脱离操作系统python版本。您可以尝试pyenv,pyenv virtualenvs,或某些人更喜欢pipenv。他们将完全一样。
杰珀

@Jepper如果您需要一个全新的Python来使用Ansible,那将是一场失败的战斗。(而且我当时使用的是pyenv,但仍然存在这些问题:-)
Stuart Watt

127

要过滤字典列表,可以将selectattr过滤器equalto test一起使用:

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

以上要求Jinja2 v2.8或更高版本(与Ansible版本无关)。


Ansible也有测试matchsearch,它们使用正则表达式:

match在字符串中将要求完全匹配,而在字符串search中将需要匹配。

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

要将字典列表简化为字符串列表,以便仅获取addr字段列表,可以使用map过滤器

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

或者,如果要用逗号分隔的字符串:

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

结合起来,看起来像这样。

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

1
如果您希望将它们作为列表而不是用逗号分隔的字符串,则还可以使用:{{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | list }}
TrinitronX

1
您提供的链接是否发生变化?我在该页
面上

1
@activedecay看起来已经从该页面消失了,是的。我现在唯一能找到的提及是在此页面上:docs.ansible.com/ansible/latest/user_guide/…我更新了链接,谢谢!
udondan

19

不一定更好,但是由于可以选择,这是使用Jinja语句的方法

- 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"
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.