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

基于两个Ansible Facts列表匹配生成目标结构化列表

如何基于两个Ansible Facts列表生成关联后的结构化列表?

需求说明

需要基于两个Ansible Facts列表生成新的结构化列表,通过提取子串进行匹配关联,并修改指定字段的格式。

输入数据

第一个Facts列表:ansible_facts["ansible_net_virtual-systems"][0].vsys_zonelist

{
    "ansible_facts": {
        "ansible_net_virtual-systems": [
            {
                "vsys_zonelist": [
                    "L3_v0123_Zone1",
                    "L3_v0124_Zone2",
                    "L3_v0125_Zone3",
                    "L3_Trans_v0020_Zone4"  
                ]
            }
        ]
    }
}

第二个Facts列表:ansible_facts.ansible_net_routing_table

{
    "ansible_facts": {
        "ansible_net_routing_table": [
            {
                "virtual_router": "Internal",
                "destination": "10.12.123.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.123",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.124.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.124",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.125.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.125",
                "route_table": "unicast"
            },
            {
                "virtual_router": "Internal",
                "destination": "10.12.20.0/24",
                "nexthop": "0.0.0.0",
                "metric": "10",
                "flags": "  Oi  ",
                "age": "3924798",
                "interface": "ae1.20",
                "route_table": "unicast"
            }
        ]
    }
}

匹配规则与目标格式

匹配规则

  • 从第一个列表的Zone名称中提取v开头的子串(如v0123),去掉开头的v和前导零后得到数字后缀(如123)
  • 匹配第二个列表中interface字段的后缀(如ae1.123中的123),关联对应的destination地址
  • 将Zone名称修改为指定格式:L3_v0123_Zone1 → n-x-123-Zone1

目标格式

{
    "result_list": [
        {
            "name": "n-x-123-Zone1",
            "destination": "10.12.123.0/24"
        },
        {
            "name": "n-x-124-Zone2",
            "destination": "10.12.124.0/24"
        },
        {
            "name": "n-x-125-Zone3",
            "destination": "10.12.125.0/24"
        },
        {
            "name": "n-x-20-Zone4",
            "destination": "10.12.20.0/24"
        }
    ]
}

尝试过的方法

以下Playbook未能成功生成目标列表:

- name: DEBUG list with split and loop
  ansible.builtin.debug:
    # creates
    # n-x-01-Name
    # but no list(!), just messages, but could be useful to create a loop
    msg: "n-x-{% if item.split('_')[1].startswith('Client') %}{{ item[3:100] }}{% else %}{{ item.split('_')[1] | regex_replace('v','') }}-{% endif %}{% if item.split('_')[2] is defined and item.split('_')[2].startswith('Trans') %}{{ item[3:50] }}{% elif item.split('_')[1].startswith('Clients')%}{% else %}{{ item[9:100] | default('') }}{% endif %}"
  loop: '{{ ansible_facts["ansible_net_virtual-systems"][0].vsys_zonelist }}'
  delegate_to: 127.0.0.1

- name: create extract_interface
  ansible.builtin.set_fact:
    # creates (also see next task) 
    # {
    #   {
    #     "interface": "ae1.123"
    #   },
    #   {
    #     "interface": "ae1.124"
    #   }
    # }
    extract_interface: "{{ ansible_facts.ansible_net_routing_table | map(attribute='interface') | map('community.general.dict_kv', 'interface') | list }}"
  delegate_to: 127.0.0.1

- name: create map_destination_to_interface
  ansible.builtin.set_fact:
    # {
    #   "ae1.123": "10.12.123.0/24",
    #   "ae1.124": "10.12.124.0/24"
    # }
    map_destination_to_interface: "{{ ansible_facts.ansible_net_routing_table | zip(extract_interface) | map('combine') | items2dict(key_name='interface', value_name='destination') }}"
  delegate_to: 127.0.0.1

解决方案

以下Playbook可以实现需求:

- name: 创建接口与目标地址的映射字典
  ansible.builtin.set_fact:
    iface_dest_map: "{{ ansible_facts.ansible_net_routing_table | items2dict(key_name='interface', value_name='destination') }}"
  delegate_to: 127.0.0.1

- name: 生成目标结构化列表
  ansible.builtin.set_fact:
    result_list: "{{ result_list | default([]) + [ { 'name': new_name, 'destination': iface_dest_map['ae1.' ~ num_suffix] } ] }}"
  loop: "{{ ansible_facts['ansible_net_virtual-systems'][0].vsys_zonelist }}"
  vars:
    # 提取Zone名称中v开头的数字部分,去除前导零
    num_suffix: "{{ item | regex_search('v(\\d+)', '\\1') | first | regex_replace('^0+', '') }}"
    # 提取Zone名称的最后一部分(如Zone1)
    zone_part: "{{ item.split('_') | last }}"
    # 拼接成指定格式的name字段
    new_name: "n-x-{{ num_suffix }}-{{ zone_part }}"
  delegate_to: 127.0.0.1

- name: 输出结果列表
  ansible.builtin.debug:
    var: result_list
  delegate_to: 127.0.0.1

步骤说明

  1. 创建映射字典:直接使用items2dict将路由表中的interface作为键,destination作为值,生成一个可快速查找的字典,简化后续匹配逻辑。
  2. 遍历Zone列表生成结果:
    • 用regex_search提取Zone名称中v后面的数字串,再用regex_replace去掉前导零,得到匹配接口后缀的数字
    • 用split('_') | last提取Zone名称的最后一部分(如Zone1)
    • 拼接成指定格式的name字段
    • 通过ae1.{{ num_suffix }}作为键,从映射字典中取出对应的destination,将结构化数据添加到结果列表中
  3. 输出结果:通过debug任务查看最终生成的result_list

内容的提问来源于stack exchange,提问作者marcb4

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:51:16