You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

说明

  1. 一次性过滤出活跃且含IPv4的网卡,避免重复处理ansible_facts
  2. 通过combine给每个网卡信息添加cidr字段,直接完成网络段与前缀的拼接
  3. 用extract提取目标字段,再转为字典格式,方便后续调用
  4. 最终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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:12:40