Ansible如何按key存在性、group_names过滤字典并保留指定键
Ansible 组件配置过滤实现
需求梳理
已定义的components变量如下:
components: comp_one: name: first_component remote_server_path: "/tmp/path/one" binaries: - test - test_two comp_two: name: second_component remote_server_path: "/tmp/path/two" binaries: - ed_test - ed_test_2 comp_three: name: third_component remote_server_path: "/tmp/path/three"
需要实现三个处理逻辑:
- 过滤掉
components下不存在binaries键的子项(如示例中的comp_three) - 以Ansible内置变量
group_names(当前主机所属的主机组列表)为基准,过滤每个组件的binaries列表,仅保留同时存在于group_names中的条目 - 每个保留的子项仅保留
remote_server_path和过滤后的binaries两个键,移除其余冗余字段
参考hosts.yaml配置:
--- all: children: kubernetes_dev: children: ed_test: hosts: host_one: ansible_host: XXX.XXX.XXX.XXX ansible_ssh_user: ansible test_two: hosts: host_one: ansible_host: XXX.XXX.XXX.XXX ansible_ssh_user: ansible test: hosts: host_one: ansible_host: XXX.XXX.XXX.XXX ansible_ssh_user: ansible
预期输出为:
comp_one: remote_server_path: "/tmp/path/one" binaries: - test - test_two comp_two: remote_server_path: "/tmp/path/two" binaries: - ed_test
目前已实现无binaries键项的过滤,但未完成binaries列表过滤和字段裁剪。
实现方案
直接通过Jinja2逻辑一次性完成所有处理,不需要拆分多步任务,可读性和执行效率更高,输出完全匹配预期:
- name: 生成并输出处理完成的组件配置 ansible.builtin.debug: var: final_components vars: final_components: >- {% set result = {} %} {% for comp_key, comp_val in components.items() %} {% if comp_val.binaries is defined %} {% set _ = result.update({ comp_key: { 'remote_server_path': comp_val.remote_server_path, 'binaries': comp_val.binaries | intersect(group_names) } }) %} {% endif %} {% endfor %} {{ result }}
逻辑说明
- 遍历
components字典时直接跳过不存在binaries键的项,完成第一层过滤 intersect(group_names)是Ansible内置的列表交集过滤器,会自动保留binaries列表中同时存在于当前主机group_names里的条目;示例中父组kubernetes_dev不在任何binaries列表中,不会对结果产生干扰- 构建新的组件值时仅写入
remote_server_path和过滤后的binaries字段,自动丢弃name等冗余字段 - 最终生成的
result是标准字典结构,可以直接在后续任务中引用
如果偏好纯过滤器链的写法(无显式循环),也可以使用如下版本,效果完全一致:
- name: 生成并输出处理完成的组件配置 ansible.builtin.debug: var: final_components vars: valid_comps: "{{ components | dict2items | selectattr('value.binaries', 'defined') | list }}" comp_kv: "{{ valid_comps | map(attribute='key') | list }}" comp_vals: "{{ valid_comps | map(attribute='value') | map('json_query', '{\"remote_server_path\": remote_server_path, \"binaries\": binaries}') | list }}" final_components: "{{ dict(comp_kv | zip(comp_vals)) | combine({'*': {'binaries': item.binaries | intersect(group_names)}}, recursive=True) }}"
内容的提问来源于stack exchange,提问作者Ares
相关产品推荐
相关产品推荐

