如何用Ansible过滤器按指定条件与默认值生成目标主机列表?
解决方案:用Jinja过滤器优雅筛选符合条件的Ansible主机列表
可以通过组合Jinja过滤器链实现需求,完全替代冗长的循环写法,直接生成符合以下两个条件的主机列表:
- 属于
cdsre组 - 要么未定义
foo属性,要么foo属性值为baz
核心过滤器写法
some_servers: "{{ groups['cdsre'] | map('extract', hostvars) | selectattr('foo', 'default', 'baz') | selectattr('foo', '==', 'baz') | map(attribute='inventory_hostname') | list }}"
过滤器逻辑说明
groups['cdsre']: 获取cdsre组下的所有主机名map('extract', hostvars): 将主机名转换为对应的主机变量对象selectattr('foo', 'default', 'baz'): 对每个主机变量,如果foo未定义,就默认赋值为baz;已定义的则保留原值selectattr('foo', '==', 'baz'): 筛选出foo值为baz的主机(包含刚才被默认赋值的未定义foo的主机)map(attribute='inventory_hostname'): 提取符合条件主机的inventory_hostname字段list: 将结果转换为列表
完整Playbook示例
--- - hosts: localhost gather_facts: false tasks: - set_fact: # 用过滤器链实现的优雅写法 some_servers: "{{ groups['cdsre'] | map('extract', hostvars) | selectattr('foo', 'default', 'baz') | selectattr('foo', '==', 'baz') | map(attribute='inventory_hostname') | list }}" # 原有的仅匹配已定义foo=baz的写法 foo_matched_servers: "{{ groups['cdsre'] | map('extract', hostvars) | selectattr('foo', 'defined') | selectattr('foo', '==', 'baz') | map(attribute='inventory_hostname') | list}}" - debug: var: some_servers - debug: var: foo_matched_servers
验证输出
执行后,some_servers的输出会和你原来循环写法的结果完全一致:
"some_servers": [ "ovh-vm1", "ovh-vm2", "ovh-vm3", "ovh-vm6", "ovh-vm7", "oracle-vm4", "oracle-vm5" ]
备选写法(用自定义筛选条件)
如果需要更直观表达“或”逻辑,也可以用select结合lambda表达式:
some_servers: "{{ groups['cdsre'] | map('extract', hostvars) | select(item => item.foo is not defined or item.foo == 'baz') | map(attribute='inventory_hostname') | list }}"
内容的提问来源于stack exchange,提问作者Chris Doyle
相关产品推荐
相关产品推荐

