Ansible实现双层嵌套循环的方法求助
Ansible实现双层嵌套循环的方法求助
看起来你已经搞定了第一层遍历vlans字典的操作,但卡在了嵌套遍历mode这一步对吧?我来帮你捋清楚怎么实现这个需求——毕竟你的变量结构里,每个VLAN的mode又是一个存着端口模式和端口列表的字典,确实需要多做一步处理。
首先先明确你的变量结构:vlans是一个顶层字典,每个键(比如Servers、Clients)对应的值里,mode又是一个子字典——键是端口模式(tagged/untagged),值是逗号分隔的端口字符串。要实现每个端口单独执行配置任务,我们得先把这些嵌套的结构拆成扁平的、每个条目对应一个端口配置的列表。
解决方案:先预处理变量,再循环执行任务
我推荐用set_fact先把变量转换成适合循环的结构,把每个端口的VLAN ID、端口号、端口模式一一对应起来:
- name: 预处理VLAN变量,生成单端口配置列表 set_fact: vlan_port_list: | {% set result = [] %} {% for vlan_name, vlan_data in vlans.items() %} {% # 跳过没有mode配置的VLAN,比如Printers %} {% if vlan_data.mode is defined %} {% # 遍历每个端口模式(tagged/untagged) %} {% for mode, ports_str in vlan_data.mode.items() %} {% # 把逗号分隔的端口字符串拆成单个端口 %} {% for port in ports_str.split(',') %} {% set _ = result.append({ 'vlan_id': vlan_data.vlan_id, 'port_id': port.strip(), # 去掉端口号前后可能的空格 'port_mode': mode }) %} {% endfor %} {% endfor %} {% endif %} {% endfor %} {{ result }}
有了这个预处理后的vlan_port_list,接下来的配置任务就简单了,直接循环这个列表就行:
- name: 配置VLAN端口成员 arubaoss_vlan: command: config_vlan_port config: "create" vlan_id: "{{ item.vlan_id }}" port_id: "{{ item.port_id }}" port_mode: "{{ item.port_mode | regex_replace('^tagged$', 'POM_TAGGED_STATIC') | regex_replace('^untagged$', 'POM_UNTAGGED') | regex_replace('^forbid$', 'POM_FORBIDDEN') }}" api_version: "{{ ansible_api_version }}" use_ssl: "{{ ansible_use_ssl }}" port: "{{ ansible_port }}" host: "{{ ansible_host }}" username: "{{ ansible_user }}" password: "{{ ansible_password }}" loop: "{{ vlan_port_list }}" tags: - vlans - vlans_mode
验证预处理结果
你可以加个debug任务来确认预处理后的列表是否符合预期:
- name: 调试预处理后的VLAN端口配置 debug: msg: "VLAN {{ item.vlan_id }} - 端口{{ item.port_id }} - 模式{{ item.port_mode }}" loop: "{{ vlan_port_list }}" tags: - debug
这个debug任务会输出类似这样的内容,每个端口都是单独的条目,完全符合我们的需求:
ok: [sw39stack01.group.corp] => (item={'vlan_id': 10, 'port_id': '1/1', 'port_mode': 'tagged'}) => { "msg": "VLAN 10 - 端口1/1 - 模式tagged" } ok: [sw39stack01.group.corp] => (item={'vlan_id': 10, 'port_id': '1/2', 'port_mode': 'tagged'}) => { "msg": "VLAN 10 - 端口1/2 - 模式tagged" } ok: [sw39stack01.group.corp] => (item={'vlan_id': 10, 'port_id': '1/3', 'port_mode': 'untagged'}) => { "msg": "VLAN 10 - 端口1/3 - 模式untagged" } ...
为什么不用with_subelements?
你之前试过的with_subelements其实也能用,但需要先把mode字典转换成列表结构(比如把{'tagged': '1/1,1/2'}变成[{'mode': 'tagged', 'ports': '1/1,1/2'}]),但这样还是绕不开拆分端口字符串的步骤,反而不如直接用set_fact预处理来得直观。
这个方法应该能完美解决你的嵌套循环需求,你可以试试这个方案~
备注:内容来源于stack exchange,提问作者Isopote42
相关产品推荐
相关产品推荐

