Ansible - 如何在不同键的 yaml 中使用 selectattr

jka*_*vas 3 python jinja2 ansible

我想通过解析 yaml 并过滤 Ansible 中的某些键来做一件简单的事情(我认为这应该很容易)。

我的 yaml 文件如下所示:

---

- vm: "vm1"
  ip: 10.10.10.1
- vm: "vm2"
  ip: 10.10.10.2
- test_vm: something
- another_vm: something_other
Run Code Online (Sandbox Code Playgroud)

所以我想不是像这样的表达

lookup('file','my_file.yaml') | from_yaml | selectattr('vm','search','vm1')|list
Run Code Online (Sandbox Code Playgroud)

会工作,但它给出了一个错误

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"}
Run Code Online (Sandbox Code Playgroud)

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

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

Run Code Online (Sandbox Code Playgroud)

如果我尝试搜索 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 ...
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

非常感谢。

Zei*_*tor 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') }}"
Run Code Online (Sandbox Code Playgroud)

这使:

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   
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

{{ test_var | selectattr('vm','defined') |selectattr('vm','equalto','vm1') | list }} 
Run Code Online (Sandbox Code Playgroud)