我正在努力尝试做一件简单的事情(我认为这应该很容易),解析 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 ? 有办法吗?
提前非常感谢。
过滤器是否期望列表中的所有字典具有相同的键?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
补充 Zeitounator 答案的此编辑:
更准确地说,它期望列表中的所有字典都具有您正在选择的属性。
对于所有过滤功能来说,通过并非所有元素都定义的属性来选择对象并不是 100% 正确:
{{ test_var | selectattr('vm','defined') |selectattr('vm','equalto','vm1') | list }}