Ansible中字典值为列表的字典列表嵌套循环实现问题
问题
我有一个字典列表,其中:
- 字典的键是Cisco交换机名称
- 字典的值是对应交换机上已配置的VLAN ID列表
数据结构如下:
"switch_vlan_ids": [ { "switch01": ["1", "10", "30", "50"] }, { "switch02": ["1", "20", "40", "60"] } ]
我的需求是遍历每台交换机,再遍历每台交换机上的每个VLAN ID,将ID传入命令(比如show vlan {{id}})。最终要连接多台交换机,验证对应VLAN ID的端口是否已配置,未配置则报错。
尝试过的方法及问题
- 嵌套循环作用域问题
我尝试用嵌套循环,但内层循环提示外层的tor_item未定义:
- name: 外层循环 - 遍历TOR交换机 ansible.builtin.debug: msg: "TOR名称: {{ tor_item.key }}" loop: "{{ switch_vlan_ids | map('dict2items') | flatten }}" loop_control: loop_var: tor_item - name: 内层循环 - 遍历VLAN ID ansible.builtin.debug: msg: "VLAN ID: {{ id_item.value }}" loop: "{{ tor_item.value }}" loop_control: loop_var: id_item
- 直接遍历ID丢失交换机信息
我试过直接提取所有VLAN ID,但这样会丢失对应的交换机名称,报错时无法定位到具体设备:
- name: 提取所有VLAN ID值 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
我还试了用Jinja过滤器写循环,但不知道怎么把交换机和VLAN的信息传递给API调用,最终放弃:
- name: blah set_fact: | {% for switch in switch_vlan_ids %} {% for name,ids in switch.items() %} {% for id in ids %}
解决方案
方法1:用subelements过滤器实现关联循环
Ansible的subelements过滤器可以把交换机名称和对应的VLAN列表绑定,一次循环就能拿到两者的信息,完美解决嵌套循环的作用域问题:
- name: 遍历交换机及对应VLAN ID ansible.builtin.debug: msg: "交换机: {{ item.0.key }}, VLAN ID: {{ item.1 }}" loop: "{{ switch_vlan_ids | map('dict2items') | flatten | subelements('value') }}"
这里map('dict2items') | flatten把原字典列表转成[{key: 'switch01', value: [...]}, ...]的格式,再用subelements('value')把每个交换机的VLAN列表拆分成独立项,最终循环的item是元组(交换机信息, VLAN ID)。
方法2:生成统一格式的组合列表再遍历
如果需要更灵活的控制(比如后续要执行CLI命令、委托到对应交换机),可以先把数据转换成{switch: 名称, vlan: ID}的结构,再遍历:
- name: 生成交换机-VLAN组合列表 ansible.builtin.set_fact: switch_vlan_pairs: > {%- set pairs = [] -%} {%- for switch in switch_vlan_ids -%} {%- for name, vlans in switch.items() -%} {%- for vlan in vlans -%} {%- do pairs.append({'switch': name, 'vlan': vlan}) -%} {%- endfor -%} {%- endfor -%} {%- endfor -%} {{ pairs }} - name: 执行VLAN验证命令 ansible.netcommon.cli_command: command: "show vlan {{ item.vlan }}" register: vlan_check_results delegate_to: "{{ item.switch }}" loop: "{{ switch_vlan_pairs }}" - name: 检查VLAN配置状态,未配置则报错 ansible.builtin.fail: msg: "交换机 {{ item.item.switch }} 的VLAN {{ item.item.vlan }} 未配置" when: "'VLAN not found' in item.stdout" loop: "{{ vlan_check_results.results }}"
这种方式把数据转成易处理的结构,后续执行命令时可以直接通过delegate_to指定目标交换机,报错信息也能精准定位到具体设备和VLAN ID。
内容的提问来源于stack exchange,提问作者piercjs
相关产品推荐
相关产品推荐

