Ansible - 如何将 selectattr 与不同键的 yaml 一起使用

问题描述 投票:0回答:2

我正在努力尝试做一件简单的事情(我认为这应该很容易),解析 yaml 并在 Ansible 中过滤某些键。

我的 yaml 文件如下所示:

---

- vm: "vm1"
  ip: 10.10.10.1
- vm: "vm2"
  ip: 10.10.10.2
- test_vm: something
- another_vm: something_other

所以我想而不是像

这样的表达
lookup('file','my_file.yaml') | from_yaml | selectattr('vm','search','vm1')|list

可以工作,但会出现如下错误

fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ lookup('file','{{sysfile}}') | from_yaml | selectattr('vm','search','vm1')|list}}): expected string or bytes-like object"}

如果我删除 test_vm 和 another_vm 键,它就可以正常工作。

ok: [localhost] => {
    "msg": [
        {
            "ip": "10.10.10.1",
            "vm": "vm1"
        }
    ]
}

如果我尝试搜索 test_vm 密钥,它会失败并显示:

fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'test_vm'\n\nThe error appears to be ...

selectattr 过滤器是否期望列表中的所有字典都具有相同的键?因为无法使用 Jinja2 过滤自定义字典列表没有任何意义。

例如,如果我有一个更复杂的 yaml(不是那么平坦),我是否只能在 Ansible 中搜索和过滤?

例如,如果我有一个 yaml 看起来像这样:

---

- vm: "vm1"
  ip: 10.10.10.1
- vm: "vm2"
  ip: 10.10.10.2
- test_vm: something
   - process_1: X
   - process_2: Y
   - process_3: Z
- another_vm: something_other

例如,我如何快速过滤 process_2 ? 有办法吗?

提前非常感谢。

python ansible jinja2
2个回答
8
投票

selectattr
过滤器是否期望列表中的所有字典具有相同的键?

更准确地说,它期望列表中的所有字典都具有您正在选择的属性。如果列表中并非所有字典都有它,您必须首先过滤掉未定义的项目。这也可以通过

selectattr
来完成。 (感谢@Randy 自我最初的回答以来使这一点变得更加清晰)。

在您的情况下,

json_query
过滤器(实现jmespath)有时也可以以更紧凑的方式完成这项工作。但它不是核心过滤器,需要安装
community.general
集合

以下是从您的上述需求中摘取的一些示例,这些示例均使用核心过滤器和

json_query
解决方案来解决。

剧本:

---
- name: "Filter data with core filters or json query"
  hosts: "localhost"
  gather_facts: false

  vars:
    # Your initial data on a single line for legibility
    test_var: [{"vm":"vm1","ip":"10.10.10.1"},{"vm":"vm2","ip":"10.10.10.2"},{"test_vm":"something","process_1":"X","process_2":"Y","process_3":"Z"},{"another_vm":"something_other"}]

  tasks:
    - name: Get objects having vm==vm1
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('vm', 'defined') | selectattr('vm', '==', 'vm1') | list }}
          With json_query: {{ test_var | json_query("[?vm=='vm1']") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get all objects having vm attribute
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('vm', 'defined') | list }}
          With json_query: {{ test_var | json_query("[?vm]") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get all objects having process_2 attribute
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('process_2', 'defined') | list }}
          With json_query: {{ test_var | json_query("[?process_2]") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

    - name: Get only a list of process_2 attributes
      vars:
        msg: |-
          With core filters: {{ test_var | selectattr('process_2', 'defined') | map(attribute='process_2') | list }}
          With json_query: {{ test_var | json_query("[].process_2") | list }}
      debug:
        msg: "{{ msg.split('\n') }}"

给出:

PLAY [Filter data with core filters or json query] *********************************************************************

TASK [Get objects having vm==vm1] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}]",
        "With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}]"
    ]
}

TASK [Get all objects having vm attribute] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]",
        "With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]"
    ]
}

TASK [Get all objects having process_2 attribute] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]",
        "With json_query: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]"
    ]
}

TASK [Get only a list of process_2 attributes] *********************************************************************
ok: [localhost] => {
    "msg": [
        "With core filters: ['Y']",
        "With json_query: ['Y']"
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

7
投票

补充 Zeitounator 答案的此编辑

更准确地说,它期望列表中的所有字典都具有您正在选择的属性。

对于所有过滤功能来说,通过并非所有元素都定义的属性来选择对象并不是 100% 正确:

{{ test_var | selectattr('vm','defined') |selectattr('vm','equalto','vm1') | list }} 
© www.soinside.com 2019 - 2024. All rights reserved.