如何在Ansible中高效访问嵌套JSON对象?附Nautobot实操场景
问题描述
我有如下JSON结构,能访问到二级层级,但无法深入到destination_services这类嵌套列表的下层,点语法无效,推测是列表、字典混合结构导致的。
原始JSON片段:
"json": { "count": 5, "next": null, "previous": null, "results": [ { "action": "pass", "application_groups": [], "applications": [], "created": "2024-06-20T09:53:20.139779+02:00", "custom_fields": {}, "description": "", "destination_address_groups": [], "destination_addresses": [], "destination_service_groups": [], "destination_services": [ { "created": "2024-06-18T02:00:00+02:00", "custom_fields": {}, "description": "", "display": "ICMP (ICMP)", "id": "c52f9be9-b4ca-4dd4-8993-2615c2fe004f", "ip_protocol": "ICMP", "last_updated": "2024-06-18T10:52:44.698368+02:00", "name": "ICMP", "natural_slug": "icmp__icmp_c52f" } ] } ] }
我执行的Ansible任务:
- name: API CALL (Nautobot GET rules) ansible.builtin.uri: url: https://{{ nautobot_ip }}/api/plugins/firewall/policy-rule/?depth=4 method: GET validate_certs: false headers: Authorization: Token {{ nautobot_token }} register: firewall_rules - name: SET FACT (Firewall policy rules) ansible.builtin.set_fact: firewall_policy_rules: "{{ firewall_rules['json']['results'] | json_query('[].{ dst_services: destination_services, dst_services_names: destination_services.names } ') }}"
我的目标是创建可用于后续任务的完整防火墙规则映射字典,部分对象层级比destination_services更深。期望得到如下格式的结果(同时保留完整的destination_services列表和提取出的name属性):
"ansible_facts": { "firewall_policy_rules": [ { "destination_services": [ { "created": "2024-06-18T02:00:00+02:00", "custom_fields": {}, "description": "", "display": "ICMP (ICMP)", "id": "c52f9be9-b4ca-4dd4-8993-2615c2fe004f", "ip_protocol": "ICMP", "last_updated": "2024-06-18T10:52:44.698368+02:00", "name": "ICMP", "natural_slug": "icmp__icmp_c52f" } ], "dst_services_names": "ICMP" } ] }
解决方案
1. 修正JSON Query语法
问题出在destination_services.names的写法上:destination_services是列表类型,不能直接用点语法访问内部属性,必须先遍历列表元素(用[*])。
根据你的需求,分两种情况处理:
- 如果每个规则的
destination_services只有一个元素,直接取第一个元素的name:- name: SET FACT (Firewall policy rules) ansible.builtin.set_fact: firewall_policy_rules: "{{ firewall_rules['json']['results'] | json_query('[].{ destination_services: destination_services, dst_services_names: destination_services[0].name } ') }}" - 如果可能有多个服务,需要将所有
name拼接成字符串(用join(', ')):- name: SET FACT (Firewall policy rules) ansible.builtin.set_fact: firewall_policy_rules: "{{ firewall_rules['json']['results'] | json_query('[].{ destination_services: destination_services, dst_services_names: destination_services[*].name | join(\", \") } ') }}"
2. 处理更深层级的嵌套结构
如果有更复杂的多层嵌套(比如destination_services里还有子列表/字典),可以继续用[*]遍历,或者结合Ansible的其他过滤器(比如map、flatten):
例如要提取destination_services下所有子元素的ip_protocol:
- name: Extract deep nested values ansible.builtin.set_fact: service_protocols: "{{ firewall_rules['json']['results'] | json_query('[].destination_services[*].ip_protocol') | flatten }}"
3. 保留完整结构并扩展属性
如果需要保留原规则的所有字段,同时添加提取的属性,不需要重新构造整个字典,直接用combine过滤器:
- name: Add extracted fields to original rules ansible.builtin.set_fact: firewall_policy_rules: "{{ firewall_rules['json']['results'] | map('combine', {'dst_services_names': item.destination_services | map(attribute='name') | join(', ')}) | list }}" loop: "{{ firewall_rules['json']['results'] }}"
内容的提问来源于stack exchange,提问作者kuda
相关产品推荐
相关产品推荐

