Ansible - 当字典值是列表时,带有字典列表的嵌套循环

问题描述 投票:0回答:1

我有一个字典列表。

  • 字典键是 Cisco 交换机名称
  • 字典值是在相应交换机上配置的 vlan ID
"switch_vlan_ids": [
    {
        "switch01": ["1", "10", "30", "50"]
    },
    {
        "switch02": ["1", "20", "40", "60"]
    }
]

我试图循环遍历每个开关,并在每个开关上循环遍历每个 ID,以便我可以将此 ID 传递给命令,例如

show vlan {{id}}

最终目标,连接到一堆交换机,验证每个交换机是否为每个 vlan ID 配置了交换机端口,如果没有,则报告错误/失败。

我尝试了嵌套循环,但是内部循环抱怨外循环loop_var未定义

 - name: Outer loop - Iterate through TOR Switches
   ansible.builtin.debug:
     msg: "TOR Name: {{ tor_item.key }}"
   loop: "{{ switch_vlan_ids | map('dict2items') | flatten }}"
   loop_control:
     loop_var: tor_item

 - name: Inner loop - Iterate through VLAN IDs
   ansible.builtin.debug:
     msg: "VLAN ID: {{ id_item.value }}"
   loop: "{{ tor_item.value }}"
   loop_control:
     loop_var: id_item

我也尝试过循环遍历 ID 值,但是,这不会给出开关名称,因此,如果出现错误,我无法报告带有错误的开关名称

- name: Set fact to loop through the tor_vlan_is_list values
  ansible.builtin.set_fact:
    switch_vlan_id_values: "{{ switch_vlan_ids | json_query('[].values(@)') | flatten }}"
- debug: var=switch_vlan_id_list_values

以上回报

"switch_vlan_id_values": ["1", "10", "30", "50", "1", "20", "40", "60"]

我什至尝试过如下所示的 Jinja 过滤器,但放弃了它,因为我不知道如何将值传递给 API 调用

- name: blah
  set_fact: | 
    {% for switch in switch_vlan_ids %}
    {% for name,ids in switch.items() %}
    {% for id in ids %}
list loops ansible nested-loops
1个回答
0
投票

重构您的数据,而不是:

"switch_vlan_ids": [
    {
        "switch01": ["1", "10", "30", "50"]
    },
    {
        "switch02": ["1", "20", "40", "60"]
    }
]

你有:

"switch_vlan_ids": [
    {
        "name": "switch01",
        "vlans": ["1", "10", "30", "50"]
    },
    {
        "name": "switch02",
        "vlans": ["1", "20", "40", "60"]
    }
]

现在我们可以使用

subelements
过滤器来实现嵌套循环的效果。如果我们修改昨天的解决方案,那么我们就有:

def transform_vlan_list(vlan_list):
    return [
        {
            "name": switch[0],
            "vlans": [int(vlan["id"]) for vlan in switch[1].values()],
        }
        for x in vlan_list
        for switch in x.items()
    ]


class FilterModule:
    def filters(self):
        return {"transform_vlan_list": transform_vlan_list}

然后我们可以写一个这样的剧本:

- hosts: localhost
  gather_facts: false
  vars_files:
    - vlans.json
  tasks:
    - loop: "{{ tor_vlan_list | transform_vlan_list | subelements('vlans') }}"
      debug:
        msg:
          - switch: "{{ item.0.name }}"
          - vlan id: "{{ item.1 }}"

并获取输出:


PLAY [localhost] ***************************************************************

TASK [debug] *******************************************************************
ok: [localhost] => (item=[{'name': 'switch_01', 'vlans': [1, 10, 30, 50]}, 1]) => {
    "msg": [
        {
            "switch": "switch_01"
        },
        {
            "vlan id": "1"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_01', 'vlans': [1, 10, 30, 50]}, 10]) => {
    "msg": [
        {
            "switch": "switch_01"
        },
        {
            "vlan id": "10"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_01', 'vlans': [1, 10, 30, 50]}, 30]) => {
    "msg": [
        {
            "switch": "switch_01"
        },
        {
            "vlan id": "30"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_01', 'vlans': [1, 10, 30, 50]}, 50]) => {
    "msg": [
        {
            "switch": "switch_01"
        },
        {
            "vlan id": "50"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_02', 'vlans': [1, 20, 40, 60]}, 1]) => {
    "msg": [
        {
            "switch": "switch_02"
        },
        {
            "vlan id": "1"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_02', 'vlans': [1, 20, 40, 60]}, 20]) => {
    "msg": [
        {
            "switch": "switch_02"
        },
        {
            "vlan id": "20"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_02', 'vlans': [1, 20, 40, 60]}, 40]) => {
    "msg": [
        {
            "switch": "switch_02"
        },
        {
            "vlan id": "40"
        }
    ]
}
ok: [localhost] => (item=[{'name': 'switch_02', 'vlans': [1, 20, 40, 60]}, 60]) => {
    "msg": [
        {
            "switch": "switch_02"
        },
        {
            "vlan id": "60"
        }
    ]
}
© www.soinside.com 2019 - 2024. All rights reserved.