如何在Ansible中从字典键值对生成列表并构建CIDR块
问题:Ansible提取活跃网卡信息并生成合法CIDR块
使用Ansible v2.14.3处理ansible_facts,目标是提取活跃Docker网卡的device、network、prefix字段,并将network与prefix拼接为合法CIDR块,但尝试的两种方法均失败,最终得到AnsibleUnsafeText类型数据,无法正常处理。
尝试的代码
--- - hosts: all tasks: - name: Get network interface names. set_fact: _device: "{{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | selectattr('value.active', 'true') | map(attribute='value') | map(attribute='device') | list }}" - name: Get IPv4 params of network interfaces. set_fact: _ipv4: "{{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | selectattr('value.active', 'true') | map(attribute='value') | map(attribute='ipv4') | list }}" - name: Get network address from IPv4 params. set_fact: _network: "{{ _ipv4 | map(attribute='network')}}" - name: Get network prefix from IPv4 params. set_fact: _prefix: "{{ _ipv4 | map(attribute='prefix')}}" - name: Concat network addresses and prefixes into a dictionary. set_fact: _dict: "{{ dict( _network | zip(_prefix )) | dict2items }}" - name: Get network CIDR blocks. set_fact: _cidrs: "{{_values | default([]) + '[item.key/item.value]'}}" loop: "{{ _dict }}"
最后一步的替代版本
- name: Get network CIDR blocks. vars: _cidrs: [] set_fact: _cidrs: "{{ _cidrs }} + '[{{ item.key }}/{{ item.value }}]'" loop: "{{ _dict }}"
执行输出
TASK [Debug network interface names.] ************************************* ok: [server] => { "_device": [ "br-624acf7a2c6d", "lo", "eth0" ] } TASK [Debug IPv4 params of network interfaces.] *********************************************** ok: [server] => { "_ipv4": [ { "address": "172.24.0.1", "broadcast": "172.24.255.255", "netmask": "255.255.0.0", "network": "172.24.0.0", "prefix": "16" }, { "address": "127.0.0.1", "broadcast": "", "netmask": "255.0.0.0", "network": "127.0.0.0", "prefix": "8" }, { "address": "192.168.0.2", "broadcast": "192.168.0.255", "netmask": "255.255.255.0", "network": "192.168.0.0", "prefix": "24" } ] } TASK [Debug network address from IPv4 params.] ******************************************** ok: [server] => { "_network": [ "172.24.0.0", "127.0.0.0", "192.168.0.0" ] } TASK [Debug network prefix from IPv4 params.] ***************************************** ok: [server] => { "_prefix": [ "16", "8", "24" ] } TASK [Debug dict.] *********** ok: [server] => { "_dict": [ { "key": "172.24.0.0", "value": "16" }, { "key": "127.0.0.0", "value": "8" }, { "key": "192.168.0.0", "value": "24" } ] } TASK [Debug CIDRs.] ********************* ok: [server] => { "_cidrs": "[] + '[172.24.0.0/16]' + '[127.0.0.0/8]' + '[192.168.0.0/24]'" }
解决方案
问题根源是循环拼接时误用字符串拼接而非列表操作,导致结果变为字符串而非可处理的列表。可简化流程,一次性完成所有字段提取与CIDR生成:
优化后的Playbook
--- - hosts: all tasks: - name: 提取活跃网卡信息并生成CIDR set_fact: nic_info: >- {{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | selectattr('value.active', 'true') | map(attribute='value') | map( 'combine', {'cidr': "{{ item.ipv4.network }}/{{ item.ipv4.prefix }}"} ) | map( 'extract', ['device', 'ipv4.network', 'ipv4.prefix', 'cidr'] ) | map('community.general.dict_kv', ['device', 'network', 'prefix', 'cidr']) | list }} - name: 查看结果 debug: var: nic_info
说明
- 一次性过滤出活跃且含IPv4的网卡,避免重复处理
ansible_facts - 通过
combine给每个网卡信息添加cidr字段,直接完成网络段与前缀的拼接 - 用
extract提取目标字段,再转为字典格式,方便后续调用 - 最终
nic_info为列表类型,每个元素包含完整的网卡信息,可直接处理
如果仅需单独的CIDR列表,可进一步简化:
- name: 获取所有活跃网卡的CIDR列表 set_fact: active_cidrs: >- {{ ansible_facts | dict2items | selectattr('value.ipv4', 'defined') | selectattr('value.active', 'true') | map(attribute='value.ipv4') | map('regex_replace', '^.*network: (\S+), prefix: (\d+).*$', '\1/\2') | list }}
内容的提问来源于stack exchange,提问作者ziv.kale
相关产品推荐
相关产品推荐

