Ansible如何从嵌套字典提取各客户的唯一服务器列表?
提取嵌套字典中每个客户的唯一服务器列表(Ansible实现)
需求
从指定的嵌套字典customers中提取每个客户的唯一服务器名称列表,无需考虑集群编号或服务器角色。
给定的嵌套字典
"customers": { "customer_1": [ { "c1_cluster_1": [ { "primary": [ "c1_server_1" ] }, { "secondaries": [ "c1_server_2", "c1_server_3" ] }, { "tiebreakers": [ "c1_server_4", "c1_server_5" ] } ] }, { "c1_cluster_2": [ { "primary": [ "c1_server_1" ] }, { "secondaries": [ "c1_server_2", "c1_server_3" ] }, { "tiebreakers": [ "c1_server_4", "c1_server_5" ] } ] }, { "c1_cluster_3": [ { "primary": [ "c1_server_1" ] }, { "secondaries": [ "c1_server_2", "c1_server_3" ] }, { "tiebreakers": [ "c1_server_4", "c1_server_5" ] } ] } ], "customer_2": [ { "c2_cluster_1": [ { "primary": [ "c2_server_1" ] }, { "secondaries": [ "c2_server_2", "c2_server_3" ] }, { "tiebreakers": [ "c2_server_4", "c2_server_5" ] } ] }, { "c2_cluster_2": [ { "primary": [ "c2_server_1" ] }, { "secondaries": [ "c2_server_2", "c2_server_3" ] }, { "tiebreakers": [ "c2_server_4", "c2_server_5" ] } ] } ] }
期望结果
customer_servers: customer_1: - "c1_server_1" - "c1_server_2" - "c1_server_3" - "c1_server_4" - "c1_server_5" customer_2: - "c2_server_1" - "c2_server_2" - "c2_server_3" - "c2_server_4" - "c2_server_5"
已尝试的方法
方法1:Jinja2模板结合set_fact
- name: use Jinja to extract only the customer names and server names from customers ansible.builtin.set_fact: cust_servers: | {% for cust in customers %} {{ cust.key }}: {% for serv in cust.value %} {% for k, v in serv.items() %} - {{v}} {% endfor %} {% endfor %} {% endfor %} - name: Convert cust_servers to a dictionary ansible.builtin.set_fact: cust_servers_dict: "{{cust_servers|from_yaml}}"
方法2:debug模块拆解字典结构
- name: print the customer dictionary component parts debug: msg: - "ClusterName is {{customers[0].key}} and it's value is" - "{{customers[0].value}}" - " ----------------------------------------------------- " - "{{customers[0].value[0].values()}}"
正确解决方案
方案1:使用json_query快速提取(简洁高效)
利用json_query递归提取所有服务器名称,结合flatten和unique去重,最终构建目标字典:
- name: 初始化结果字典 ansible.builtin.set_fact: customer_servers: {} - name: 提取每个客户的唯一服务器列表 ansible.builtin.set_fact: customer_servers: "{{ customer_servers | combine({ item.key: server_list | unique }) }}" loop: "{{ customers | dict2items }}" vars: # 递归提取当前客户的所有服务器并展平为一维列表 server_list: "{{ item.value | json_query('[].values()[][].values()') | flatten }}"
方案2:Jinja2嵌套循环提取(直观易懂)
通过多层循环遍历集群、角色,收集所有服务器后去重:
- name: 初始化结果字典 ansible.builtin.set_fact: customer_servers: {} - name: 遍历每个客户收集服务器 ansible.builtin.set_fact: customer_servers: "{{ customer_servers | combine({ cust_key: servers | unique }) }}" loop: "{{ customers | dict2items }}" vars: cust_key: "{{ item.key }}" servers: >- {% set server_list = [] %} {% for cluster_item in item.value %} {% for role_groups in cluster_item.values() | first %} {% for server_names in role_groups.values() %} {% do server_list.extend(server_names) %} {% endfor %} {% endfor %} {% endfor %} {{ server_list }}
两种方案都能得到符合预期的结果,方案1依赖json_query(需要jmespath库,Ansible默认已安装),代码更简洁;方案2纯Jinja2实现,逻辑更直观。
内容的提问来源于stack exchange,提问作者piercjs
相关产品推荐
相关产品推荐

