【问题标题】:Ansible: filter a list by its attributesAnsible:按属性过滤列表
【发布时间】:2015-08-08 15:33:38
【问题描述】:

我在 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" }}

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

【问题讨论】:

    标签: jinja2 ansible


    【解决方案1】:

    要过滤字典列表,您可以使用selectattr filterequalto test

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

    以上需要 Jinja2 v2.8 或更高版本(无论 Ansible 版本如何)。


    Ansible 还有has the tests match and search,它采用正则表达式:

    match 需要在字符串中完全匹配,而search 需要在字符串内部进行匹配。

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

    要将dicts列表减少为字符串列表,因此您只能获得addr字段的列表,您可以使用map filter

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

    或者如果你想要一个逗号分隔的字符串:

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

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

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

    【讨论】:

    • 如果您希望它们作为列表而不是逗号分隔的字符串,您也可以使用:{{ network.addresses.private_man | selectattr("type", "equalto", "fixed") | map(attribute='addr') | list }}
    • 您提供的链接有变化吗?我在该页面上找不到“匹配”和“搜索”
    • @activedecay 看起来它已经从那个页面消失了,是的。我现在能找到的唯一提及是在这个页面上:docs.ansible.com/ansible/latest/user_guide/…我更新了链接,谢谢!
    【解决方案2】:

    我已经提交了一个pull request(在 Ansible 2.2+ 中可用),通过在 Ansible 上添加 jmespath 查询支持,这将使这种情况变得更容易。在你的情况下,它会像这样工作:

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

    会返回:

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

    【讨论】:

    • 您需要在运行 json_query 过滤器之前安装“jmespath”。
    • 由于 Python 版本差异,我刚刚放弃尝试安装 jmespath。它不像在 Ansible 2.4+ 上看起来那么简单
    • @StuartWatt 您可能需要 pyenv 将自己从操作系统 python 版本中抽象出来。你可以试试 pyenv、pyenv virtualenvs,或者有些人更喜欢 pipenv。它们的工作原理都是一样的。
    • @Jepper 如果你需要一个全新的 Python 来使用 Ansible,这是一场失败的战斗。 (而且我正在使用 pyenv 并且仍然遇到这些问题 :-)
    • 那些有 python 相关问题的人:取决于正在运行的操作系统,这可能需要一个小技巧来帮助 ansible 使用正确的 python 版本。我在安装 python 2 + 3 并且 Ansible 倾向于 v2 时遇到了麻烦。您可能需要运行以下命令(例如,如果目标主机是 debian):sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 2sudo update-alternatives --set python /usr/bin/python3(假设安装了 Python2.7 和 Python3)
    【解决方案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"
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-04
      • 1970-01-01
      • 2020-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多