【问题标题】:Use json_query in Ansible to query a list of dictionaries contained within a list of dictionaries在 Ansible 中使用 json_query 查询包含在字典列表中的字典列表
【发布时间】:2021-02-16 04:27:28
【问题描述】:

我在使用 json_query 搜索以下数据结构时遇到问题,我想从中创建两个单独的列表。

列表 1 应包含来自每个字典的条目的名称键,这些条目的成员列表包含 subPath 键且其值包含特定值。

列表 2 应包含每个字典中的名称键,用于其成员列表不包含 subPath 键且名称包含特定值的条目。

到目前为止,我能找到的最接近的方法是找到那些其成员字典具有 subPath 键的字典:

- name: debug
  debug:
    msg: "{{ device_facts.gtm_a_pools | json_query(query) }}"
  vars:
    query: "[].members[?!subPath][].name"

或者没有 subPath 键:

- name: debug
  debug:
    msg: "{{ device_facts.gtm_a_pools | json_query(query) }}"
  vars:
    query: "[].members[?subPath][].name"

但是这是从成员字典中返回名称键,当我想要的是基于上述两个标准的每个 gtm_a_pools 字典中的名称键(一个具有子路径的列表和一个没有子路径的列表)。

使用以下数据结构:

  • List1 = ['a2-test_pool']
  • 列表 2 = ['aci_pool']
    "gtm_a_pools": [
        {
            "alternate_mode": "global-availability",
            "dynamic_ratio": "no",
            "enabled": "yes",
            "fallback_mode": "return-to-dns",
            "full_path": "/Common/a2-test_pool",
            "load_balancing_mode": "global-availability",
            "manual_resume": "no",
            "max_answers_returned": 1,
            "members": [
                {
                    "disabled": "no",
                    "enabled": "yes",
                    "limitMaxBps": 0,
                    "limitMaxBpsStatus": "disabled",
                    "limitMaxConnections": 0,
                    "limitMaxConnectionsStatus": "disabled",
                    "limitMaxPps": 0,
                    "limitMaxPpsStatus": "disabled",
                    "member_order": 0,
                    "monitor": "default",
                    "name": "a2-test_443_vs",
                    "partition": "Common",
                    "ratio": 1,
                    "subPath": "test-dmz-dc1-pair:/Common"
                },
                {
                    "disabled": "no",
                    "enabled": "yes",
                    "limitMaxBps": 0,
                    "limitMaxBpsStatus": "disabled",
                    "limitMaxConnections": 0,
                    "limitMaxConnectionsStatus": "disabled",
                    "limitMaxPps": 0,
                    "limitMaxPpsStatus": "disabled",
                    "member_order": 1,
                    "monitor": "default",
                    "name": "dc2-a2-test_443_vs",
                    "partition": "Common",
                    "ratio": 1,
                    "subPath": "test-dmz-dc2-pair:/Common"
                }
            ],
            "name": "a2-test_pool",
            "partition": "Common",
            "qos_hit_ratio": 5,
            "qos_hops": 0,
            "qos_kilobytes_second": 3,
            "qos_lcs": 30,
            "qos_packet_rate": 1,
            "qos_rtt": 50,
            "qos_topology": 0,
            "qos_vs_capacity": 0,
            "qos_vs_score": 0,
            "ttl": 30,
            "verify_member_availability": "yes"
        },
        {
            "alternate_mode": "round-robin",
            "dynamic_ratio": "no",
            "enabled": "yes",
            "fallback_mode": "return-to-dns",
            "full_path": "/Common/aci_pool",
            "load_balancing_mode": "round-robin",
            "manual_resume": "no",
            "max_answers_returned": 1,
            "members": [
                {
                    "disabled": "no",
                    "enabled": "yes",
                    "limitMaxBps": 0,
                    "limitMaxBpsStatus": "disabled",
                    "limitMaxConnections": 0,
                    "limitMaxConnectionsStatus": "disabled",
                    "limitMaxPps": 0,
                    "limitMaxPpsStatus": "disabled",
                    "member_order": 0,
                    "monitor": "default",
                    "name": "prod_dc1_servers:aci",
                    "partition": "Common",
                    "ratio": 1
                },
                {
                    "disabled": "no",
                    "enabled": "yes",
                    "limitMaxBps": 0,
                    "limitMaxBpsStatus": "disabled",
                    "limitMaxConnections": 0,
                    "limitMaxConnectionsStatus": "disabled",
                    "limitMaxPps": 0,
                    "limitMaxPpsStatus": "disabled",
                    "member_order": 1,
                    "monitor": "default",
                    "name": "prod_dc1_servers:aci",
                    "partition": "Common",
                    "ratio": 1
                }
            ],
            "name": "aci_pool",
            "partition": "Common",
            "qos_hit_ratio": 5,
            "qos_hops": 0,
            "qos_kilobytes_second": 3,
            "qos_lcs": 30,
            "qos_packet_rate": 1,
            "qos_rtt": 50,
            "qos_topology": 0,
            "qos_vs_capacity": 0,
            "qos_vs_score": 0,
            "ttl": 30,
            "verify_member_availability": "yes"
        }
    ]

【问题讨论】:

    标签: ansible json-query


    【解决方案1】:

    问:每个 gtm_a_pools 字典中的名称键基于上述两个标准(一个包含子路径的列表和一个没有子路径的列表)

    A:不是 json_query,而是迭代列表并比较 members 的数量,例如

        - set_fact:
            list1: "{{ list1|default([]) + [item.name] }}"
          loop: "{{ gtm_a_pools }}"
          when: item_length == subPath_length
          vars:
            subPath_length: "{{ item.members|map('intersect', ['subPath'])|flatten|length }}"
            item_length: "{{ item.members|length }}"
    

    给予

      list1:
      - a2-test_pool
    

    如果“没有子路径”表示“任何没有子路径的成员”

        - set_fact:
            list2: "{{ list2|default([]) + [item.name] }}"
          loop: "{{ gtm_a_pools }}"
          when: item_length != subPath_length
          vars:
            subPath_length: "{{ item.members|map('intersect', ['subPath'])|flatten|length }}"
            item_length: "{{ item.members|length }}"
    

    给予

      list2:
      - aci_pool
    

    如果 “没有 subPath” 表示 “所有没有 subPath 的成员” 下面的任务给出相同的结果

        - set_fact:
            list2: "{{ list2|default([]) + [item.name] }}"
          loop: "{{ gtm_a_pools }}"
          when: subPath_length|int == 0
          vars:
            subPath_length: "{{ item.members|map('intersect', ['subPath'])|flatten|length }}"
    

    【讨论】:

      【解决方案2】:

      谢谢你,弗拉基米尔!

      当我在等待某人的回复时,我想出了这个,所以我想我会在这里分享它。我会说这可能不一定要考虑到列表 2 的两种情况,其中我考虑了“没有 subPath 的所有成员”与“没有 subPath 的任何成员”。因此,我使用上面的解决方案在最后运行验证以处理整个负载并进行比较,并输出具有混合成员类型的任何池:

      ---
      - name: Determine if Server List product is Generic Host (static) or otherwise
        bigip_device_info:
          gather_subset:
            - gtm-servers
          provider: "{{ vcmp_guest_provider }}"
        delegate_to: localhost
        register: device_facts
      
      # server_type = generic-host vs. bigip
      # bigip = dynamic
      # generic-host = static
      - name: Set type fact
        set_fact:
          server_type: "{{ device_facts | json_query(jmesquery) | join }}"
        vars:
          jmesquery: "gtm_servers[?name == '{{ gtm_source_server }}'].product"
      
      - name: debug
        debug:
          var: server_type
      
      - name: Gather GTM pools 
        bigip_device_info:
          gather_subset:
            - gtm-a-pools
          provider: "{{ vcmp_guest_provider }}"
        delegate_to: localhost
        register: device_facts
      
      - name: Create list of pools that use discovered objects and are part of {{ gtm_source_server }}
        set_fact:
          pool_list: "{{ pool_list | default([]) + [ item.0 ] }}"
        loop: "{{ pool_name | zip(payload) | list }}"
        when:
          - item.1 | json_query('members[*].subPath') | length > 0
          - item.1 | json_query('members[*].subPath') is search(gtm_source_server)
          - server_type == "bigip"
        vars:
          pool_name: "{{ device_facts | json_query('gtm_a_pools[*].name') }}"
          payload: "{{ device_facts | json_query('gtm_a_pools[*]') }}"
        no_log: true
      
      - name: Create list of pools that use static objects and are part of {{ gtm_source_server }}
        set_fact:
          pool_list: "{{ pool_list | default([]) + [ item.0 ] }}"
        loop: "{{ pool_name | zip(payload) | list }}"
        when:
          - item.1 | json_query('members[*].subPath') | length == 0
          - item.1 | json_query('members[*].name') is search(gtm_source_server)
          - server_type == "generic-host"
        vars:
          pool_name: "{{ device_facts | json_query('gtm_a_pools[*].name') }}"
          payload: "{{ device_facts | json_query('gtm_a_pools[*]') }}"
        no_log: true
      
      - debug:
          var: pool_list
      
      - name: Check if any pools contain a mix of static and dynamic members
        set_fact:
          counter: "{{ counter | default([]) + [ item.name + ' has ' + subPath_length + ' dynamic entries and ' + member_length + ' static entries.' ] }}"
        loop: "{{ device_facts | json_query('gtm_a_pools[*]') }}"
        vars:
          subPath_length: "{{ item.members|map('intersect', ['subPath'])|flatten|length }}"
          member_length: "{{ item.members|length }}"
        when:
          - subPath_length | int > 0
          - member_length != subPath_length
        no_log: true
      
      - debug:
          msg: "{{ counter | default('No mixture found') }}"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多