Decouple cutover HF from portrait and tighten ops UI.

Portrait stays on biz-monitor; cutover create/ensure owns purpose=cutover_hf slots with project collect override, multi-interval bindings, window pause, and industrial detail UX. Also expand ZTE collect/config parsers and TextFSM for route/BGP/L2VPN/VRRP coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-19 21:11:31 +08:00
parent a65c9fc420
commit 285c19e5a3
67 changed files with 9510 additions and 723 deletions

View file

@ -155,7 +155,11 @@ def _vrf_profiles() -> list[ParseProfile]:
r"(?i)^\s*display\s+ip\s+vpn-instance\s*$",
"display ip vpn-instance",
),
"zte": ("show ip vrf", r"(?i)^\s*show\s+ip\s+vrf\s*$", "show ip vrf"),
"zte": (
"show ip vrf | one-line",
r"(?i)^\s*show\s+ip\s+vrf(?:\s*\|\s*one-line)?\s*$",
"show ip vrf",
),
}
collect_cmds: dict[str, tuple[str, str]] = {
"cisco": (
@ -194,6 +198,7 @@ def _vrf_profiles() -> list[ParseProfile]:
FieldDef("vrf_name", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("rd", length=64, role="meta", display_name="RD"),
FieldDef("protocols", length=64, role="meta", display_name="协议"),
FieldDef("vrf_id", length=32, role="meta", display_name="VRF ID"),
],
tags=["vrf", "discover"],
sort_order=order,
@ -266,6 +271,23 @@ _IFACE_BRIEF_FIELDS: list[FieldDef] = [
FieldDef("description", length=256, role="meta", display_name="描述"),
]
_IFACE_DETAIL_FIELDS: list[FieldDef] = [
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("admin", length=32, role="state", display_name="Admin"),
# Rates churn between collects — display only, never default-compare.
FieldDef("input_bps", length=32, role="counter", display_name="Input bps"),
FieldDef("output_bps", length=32, role="counter", display_name="Output bps"),
FieldDef("in_util", length=16, role="counter", display_name="In Util%"),
FieldDef("out_util", length=16, role="counter", display_name="Out Util%"),
FieldDef("bw", length=64, role="meta", display_name="BW"),
FieldDef("mtu", length=16, role="meta", display_name="MTU"),
FieldDef("ifindex", length=32, role="meta", display_name="ifindex"),
FieldDef("description", length=256, role="meta", display_name="描述"),
FieldDef("port_media", length=32, role="meta", display_name="Media"),
FieldDef("negotiation", length=32, role="meta", display_name="Negotiation"),
FieldDef("rate_period", length=16, role="meta", display_name="Rate period"),
]
_ARP_FIELDS: list[FieldDef] = [
FieldDef("ip", length=64, indexed=True, is_key=True, display_name="IP"),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
@ -294,16 +316,228 @@ _ND6_FIELDS: list[FieldDef] = [
_BGP_PEER_FIELDS: list[FieldDef] = [
FieldDef("afi", length=32, indexed=True, is_key=True, display_name="AFI", from_command_param=True),
FieldDef("neighbor", length=64, indexed=True, is_key=True, display_name="Neighbor"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF", from_command_param=True),
FieldDef("neighbor", length=128, indexed=True, is_key=True, display_name="Neighbor"),
FieldDef("as_num", length=16, role="state", display_name="AS"),
FieldDef("state", length=64, role="state", display_name="State"),
FieldDef("pfx_rcd", length=32, role="state", display_name="PfxRcd"),
# Prefix count churns between collects — display only for cutover compare.
FieldDef("pfx_rcd", length=32, role="counter", display_name="PfxRcd"),
FieldDef("ver", length=8, role="meta", display_name="Ver"),
FieldDef("msg_rcvd", length=32, role="meta", display_name="MsgRcvd"),
FieldDef("msg_send", length=32, role="meta", display_name="MsgSend"),
FieldDef("up_down", length=32, role="meta", display_name="Up/Down"),
]
_BGP_VRF_PLACEHOLDER = PlaceholderDef(
name="vrf",
schema_field="vrf",
required=True,
bind_mode="discover_select",
discover_profile_id="zte.vrf_list",
discover_value_field="vrf_name",
discover_label_field="vrf_name",
)
_BGP_NEIGHBOR_PLACEHOLDER = PlaceholderDef(
name="neighbor",
schema_field="neighbor",
required=True,
bind_mode="manual_text",
)
_OSPF_FIELDS: list[FieldDef] = [
FieldDef("process_id", length=32, indexed=True, is_key=True, display_name="Process ID"),
FieldDef("neighbor_id", length=64, indexed=True, is_key=True, display_name="Neighbor ID"),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("state", length=64, role="state", display_name="State"),
FieldDef("address", length=64, role="state", display_name="Address"),
FieldDef("dead_time", length=32, role="meta", display_name="DeadTime"),
FieldDef("pri", length=16, role="meta", display_name="Pri"),
]
_VRRP_FIELDS: list[FieldDef] = [
FieldDef("af", length=16, indexed=True, is_key=True, display_name="AF", from_command_param=True),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("vr_id", length=32, indexed=True, is_key=True, display_name="VR ID"),
FieldDef("state", length=32, role="state", display_name="State"),
FieldDef("priority", length=16, role="state", display_name="Priority"),
FieldDef("master_addr", length=128, role="state", display_name="Master"),
FieldDef("vrouter_addr", length=128, role="state", display_name="VRouter"),
FieldDef("time", length=16, role="meta", display_name="Time"),
FieldDef("flags", length=16, role="meta", display_name="Flags"),
]
_OPTICAL_FIELDS: list[FieldDef] = [
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("optic_type", length=64, role="meta", display_name="Type"),
FieldDef("wavelength", length=32, role="meta", display_name="Wavelength"),
# Optical power jitters — display only; compare status for cutover.
FieldDef("rx_power", length=64, role="counter", display_name="RxPower"),
FieldDef("tx_power", length=64, role="counter", display_name="TxPower"),
FieldDef("status", length=32, role="state", display_name="Status"),
]
_BGP_ROUTE_FIELDS: list[FieldDef] = [
FieldDef("afi", length=32, indexed=True, is_key=True, display_name="AFI", from_command_param=True),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF", from_command_param=True),
FieldDef("neighbor", length=128, indexed=True, is_key=True, display_name="Neighbor", from_command_param=True),
FieldDef("direction", length=8, indexed=True, is_key=True, display_name="Dir", from_command_param=True),
FieldDef("network", length=128, indexed=True, is_key=True, display_name="Network"),
FieldDef("next_hop", length=128, role="state", display_name="NextHop"),
FieldDef("metric", length=32, role="meta", display_name="Metric"),
FieldDef("loc_prf", length=32, role="meta", display_name="LocPrf"),
FieldDef("tag", length=32, role="meta", display_name="Tag"),
FieldDef("path", length=256, role="state", display_name="Path"),
FieldDef("status_codes", length=16, role="meta", display_name="Codes"),
FieldDef("as_num", length=16, role="state", display_name="AS"),
FieldDef("state", length=64, role="state", display_name="PeerState"),
FieldDef("pfx_rcd", length=32, role="meta", display_name="PfxRcd"),
]
_IP_ROUTE_FIELDS: list[FieldDef] = [
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF", from_command_param=True),
FieldDef("dest", length=64, indexed=True, is_key=True, display_name="Dest"),
FieldDef("gateway", length=64, indexed=True, is_key=True, display_name="Gateway"),
FieldDef("interface", length=128, is_key=True, is_interface=True, display_name="接口"),
FieldDef("owner", length=64, role="state", display_name="Owner"),
FieldDef("pri", length=16, role="meta", display_name="Pri"),
FieldDef("metric", length=32, role="meta", display_name="Metric"),
FieldDef("flags", length=16, role="meta", display_name="Flags"),
]
_IPV6_ROUTE_FIELDS: list[FieldDef] = [
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF", from_command_param=True),
FieldDef("dest", length=128, indexed=True, is_key=True, display_name="Dest"),
FieldDef("gateway", length=128, indexed=True, is_key=True, display_name="Gateway"),
FieldDef("interface", length=128, is_key=True, is_interface=True, display_name="接口"),
FieldDef("owner", length=64, role="state", display_name="Owner"),
FieldDef("pri", length=16, role="meta", display_name="Pri"),
FieldDef("metric", length=32, role="meta", display_name="Metric"),
FieldDef("flags", length=16, role="meta", display_name="Flags"),
]
_L2VPN_PW_FIELDS: list[FieldDef] = [
FieldDef("pw_name", length=128, indexed=True, is_key=True, display_name="PW"),
FieldDef("peer", length=64, indexed=True, is_key=True, display_name="Peer"),
FieldDef("state", length=32, role="state", display_name="State"),
FieldDef("fec", length=32, role="meta", display_name="FEC"),
FieldDef("pw_type", length=64, role="meta", display_name="PWType"),
FieldDef("local_label", length=32, role="meta", display_name="Llabel"),
FieldDef("remote_label", length=32, role="meta", display_name="Rlabel"),
FieldDef("vpn_owner", length=256, role="meta", display_name="VPNOwner"),
]
_L2VPN_MAC_FIELDS: list[FieldDef] = [
FieldDef("mac", length=64, indexed=True, is_key=True, display_name="MAC"),
FieldDef("vpn", length=128, indexed=True, is_key=True, display_name="VPN"),
FieldDef("vlan", length=32, role="meta", display_name="VLAN"),
FieldDef("outgoing", length=256, role="state", display_name="Outgoing"),
FieldDef("attribute", length=64, role="meta", display_name="Attribute"),
]
_EVPN_MAC_FIELDS: list[FieldDef] = [
FieldDef("network", length=256, indexed=True, is_key=True, display_name="Network"),
FieldDef("next_hop", length=128, role="state", display_name="NextHop"),
FieldDef("path", length=256, role="state", display_name="Path"),
FieldDef("metric", length=32, role="meta", display_name="Metric"),
FieldDef("loc_prf", length=32, role="meta", display_name="LocPrf"),
FieldDef("rt_prf", length=32, role="meta", display_name="RtPrf"),
FieldDef("status_codes", length=16, role="meta", display_name="Codes"),
]
_CONFIG_VRF_FIELDS: list[FieldDef] = [
FieldDef("vrf_name", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("rd", length=64, role="state", display_name="RD"),
FieldDef("address_families", length=64, role="state", display_name="AF"),
FieldDef("rt_export", length=512, role="state", display_name="RT Export"),
FieldDef("rt_import", length=512, role="state", display_name="RT Import"),
FieldDef("description", length=256, role="meta", display_name="描述"),
]
_CONFIG_IFACE_FIELDS: list[FieldDef] = [
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("admin", length=16, role="state", display_name="Admin"),
FieldDef("ip_address", length=256, role="state", display_name="IPv4"),
FieldDef("ipv6_address", length=256, role="state", display_name="IPv6"),
FieldDef("mtu", length=16, role="meta", display_name="MTU"),
FieldDef("description", length=256, role="meta", display_name="描述"),
]
_CONFIG_BGP_PEER_FIELDS: list[FieldDef] = [
FieldDef("afi", length=32, indexed=True, is_key=True, display_name="AFI"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("neighbor", length=128, indexed=True, is_key=True, display_name="Neighbor"),
FieldDef("peer_group", length=64, indexed=True, is_key=True, display_name="Group"),
FieldDef("remote_as", length=16, role="state", display_name="Remote AS"),
FieldDef("activate", length=16, role="state", display_name="Activate"),
FieldDef("update_source", length=64, role="meta", display_name="Update-Source"),
FieldDef("route_map_in", length=128, role="meta", display_name="RM In"),
FieldDef("route_map_out", length=128, role="meta", display_name="RM Out"),
]
_CONFIG_L2VPN_PW_FIELDS: list[FieldDef] = [
FieldDef("vpn_type", length=16, indexed=True, is_key=True, display_name="Type"),
FieldDef("vpn_name", length=128, indexed=True, is_key=True, display_name="VPN"),
FieldDef("pw_name", length=128, indexed=True, is_key=True, display_name="PW"),
FieldDef("peer", length=64, role="state", display_name="Peer"),
FieldDef("vcid", length=64, role="state", display_name="VCID"),
FieldDef("encapsulation", length=32, role="meta", display_name="Encap"),
FieldDef("access_point", length=128, role="meta", display_name="Access"),
FieldDef("description", length=256, role="meta", display_name="描述"),
]
_CONFIG_STATIC_ROUTE_FIELDS: list[FieldDef] = [
FieldDef("af", length=8, indexed=True, is_key=True, display_name="AF"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("prefix", length=128, indexed=True, is_key=True, display_name="Prefix"),
FieldDef("mask", length=64, indexed=True, is_key=True, display_name="Mask"),
FieldDef("next_hop", length=64, indexed=True, is_key=True, display_name="Next-Hop"),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("nexthop_vrf", length=128, role="state", display_name="Nexthop-VRF"),
FieldDef("metric", length=16, role="state", display_name="Metric"),
FieldDef("bfd", length=16, role="state", display_name="BFD"),
FieldDef("track", length=64, role="meta", display_name="Track"),
FieldDef("route_name", length=128, role="meta", display_name="Name"),
FieldDef("tag", length=32, role="meta", display_name="Tag"),
FieldDef("distance", length=16, role="meta", display_name="Distance"),
]
_CONFIG_OSPF_FIELDS: list[FieldDef] = [
FieldDef("af", length=8, indexed=True, is_key=True, display_name="AF"),
FieldDef("process_id", length=32, indexed=True, is_key=True, display_name="Process"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("area", length=64, indexed=True, is_key=True, display_name="Area"),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("area_type", length=32, role="state", display_name="Area Type"),
FieldDef("network_type", length=32, role="state", display_name="Network"),
FieldDef("cost", length=16, role="state", display_name="Cost"),
FieldDef("hello_interval", length=16, role="state", display_name="Hello"),
FieldDef("dead_interval", length=16, role="state", display_name="Dead"),
FieldDef("bfd", length=16, role="state", display_name="BFD"),
FieldDef("router_id", length=64, role="meta", display_name="Router-ID"),
FieldDef("redistribute", length=256, role="meta", display_name="Redistribute"),
]
_CONFIG_ISIS_FIELDS: list[FieldDef] = [
FieldDef("process_id", length=32, indexed=True, is_key=True, display_name="Process"),
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF"),
FieldDef("interface", length=128, indexed=True, is_key=True, is_interface=True, display_name="接口"),
FieldDef("circuit_type", length=32, role="state", display_name="Circuit"),
FieldDef("network_type", length=32, role="state", display_name="Network"),
FieldDef("ip_enable", length=8, role="state", display_name="IPv4"),
FieldDef("ipv6_enable", length=8, role="state", display_name="IPv6"),
FieldDef("metric", length=16, role="state", display_name="Metric"),
FieldDef("ipv6_metric", length=16, role="state", display_name="IPv6 Metric"),
FieldDef("passive", length=8, role="state", display_name="Passive"),
FieldDef("bfd", length=16, role="state", display_name="BFD"),
FieldDef("ipv6_bfd", length=16, role="state", display_name="IPv6 BFD"),
FieldDef("area", length=64, role="meta", display_name="Area"),
FieldDef("system_id", length=64, role="meta", display_name="System-ID"),
FieldDef("router_id", length=64, role="meta", display_name="Router-ID"),
FieldDef("is_type", length=32, role="meta", display_name="IS-Type"),
]
def _zte_status_profiles() -> list[ParseProfile]:
"""ZTE ZXROS status snapshots from lab show commands."""
@ -340,6 +574,28 @@ def _zte_status_profiles() -> list[ParseProfile]:
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.interface_detail",
vendor_key="zte",
metric_id="interface_detail",
parser_id="interface_detail",
title="Interface Detail (filtered)",
command_template=(
"show interface | include ifindex|BW|The port is|MTU|Negotiation|"
"Description|Current|Rate|Peak|Input|Output|utilization"
),
match=(
r"(?i)^\s*show\s+interface\s*\|\s*include\s+"
r".*\bifindex\b.*$"
),
textfsm_command="show interface",
description="Filtered show interface: BW/rate/util/description.",
fields=list(_IFACE_DETAIL_FIELDS),
tags=["interface", "rate", "status"],
sort_order=315,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.arp",
vendor_key="zte",
@ -371,9 +627,12 @@ def _zte_status_profiles() -> list[ParseProfile]:
command_template="show running-config if-intf",
match=r"(?i)^\s*show\s+running-config\s+if-intf\s*$",
textfsm_command="show running-config if-intf",
description="Interface VRF from running-config if-intf (ip vrf forwarding).",
description=(
"Interface VRF map for ARP enrich (aux). "
"Free-form CLI match prefers zte.config_interface (longer regex)."
),
fields=list(_IF_INTF_FIELDS),
tags=["interface", "vrf", "config", "status"],
tags=["interface", "vrf", "config", "status", "aux"],
sort_order=325,
enabled=True,
kind="collect",
@ -401,7 +660,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
parser_id="bgp_peer",
title="BGP VPNv4 Summary",
command_template="show bgp vpnv4 unicast summary",
match=r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+summary\s*$",
match=r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv4 unicast summary",
description="BGP VPNv4 peer summary (afi=vpnv4).",
fields=list(_BGP_PEER_FIELDS),
@ -417,7 +676,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
parser_id="bgp_peer",
title="BGP IPv4 Summary",
command_template="show bgp ipv4 unicast summary",
match=r"(?i)^\s*show\s+bgp\s+ipv4\s+unicast\s+summary\s*$",
match=r"(?i)^\s*show\s+bgp\s+ipv4\s+unicast\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp ipv4 unicast summary",
description="BGP IPv4 unicast peer summary (afi=ipv4).",
fields=list(_BGP_PEER_FIELDS),
@ -433,7 +692,7 @@ def _zte_status_profiles() -> list[ParseProfile]:
parser_id="bgp_peer",
title="BGP VPNv6 Summary",
command_template="show bgp vpnv6 unicast summary",
match=r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+summary\s*$",
match=r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv6 unicast summary",
description="BGP VPNv6 peer summary (afi=vpnv6).",
fields=list(_BGP_PEER_FIELDS),
@ -442,6 +701,626 @@ def _zte_status_profiles() -> list[ParseProfile]:
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.bgp_ipv6_summary",
vendor_key="zte",
metric_id="bgp_peer",
parser_id="bgp_peer",
title="BGP IPv6 Summary",
command_template="show bgp ipv6 unicast summary",
match=r"(?i)^\s*show\s+bgp\s+ipv6\s+unicast\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp ipv6 unicast summary",
description="BGP IPv6 unicast peer summary (afi=ipv6).",
fields=list(_BGP_PEER_FIELDS),
tags=["bgp", "ipv6", "status"],
sort_order=365,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.bgp_vpnv4_vrf_summary",
vendor_key="zte",
metric_id="bgp_peer",
parser_id="bgp_peer",
title="BGP VPNv4 VRF Summary",
command_template="show bgp vpnv4 unicast vrf <vrf> summary",
match=r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv4 unicast summary",
description="Per-VRF BGP VPNv4 peer summary.",
placeholders=[_BGP_VRF_PLACEHOLDER],
fields=list(_BGP_PEER_FIELDS),
tags=["bgp", "vpnv4", "vrf", "status"],
sort_order=370,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.bgp_vpnv6_vrf_summary",
vendor_key="zte",
metric_id="bgp_peer",
parser_id="bgp_peer",
title="BGP VPNv6 VRF Summary",
command_template="show bgp vpnv6 unicast vrf <vrf> summary",
match=r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv6 unicast summary",
description="Per-VRF BGP VPNv6 peer summary.",
placeholders=[_BGP_VRF_PLACEHOLDER],
fields=list(_BGP_PEER_FIELDS),
tags=["bgp", "vpnv6", "vrf", "status"],
sort_order=375,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.bgp_evpn_summary",
vendor_key="zte",
metric_id="bgp_peer",
parser_id="bgp_peer",
title="BGP L2VPN EVPN Summary",
command_template="show bgp l2vpn evpn summary",
match=r"(?i)^\s*show\s+bgp\s+l2vpn\s+evpn\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp l2vpn evpn summary",
description="BGP L2VPN EVPN peer summary (afi=evpn).",
fields=list(_BGP_PEER_FIELDS),
tags=["bgp", "evpn", "status"],
sort_order=380,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.bgp_vpls_summary",
vendor_key="zte",
metric_id="bgp_peer",
parser_id="bgp_peer",
title="BGP L2VPN VPLS Summary",
command_template="show bgp l2vpn vpls summary",
match=r"(?i)^\s*show\s+bgp\s+l2vpn\s+vpls\s+summary(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp l2vpn vpls summary",
description="BGP L2VPN VPLS peer summary (afi=vpls).",
fields=list(_BGP_PEER_FIELDS),
tags=["bgp", "vpls", "status"],
sort_order=385,
enabled=True,
kind="collect",
),
# --- Phase 1 status ---
ParseProfile(
profile_id="zte.ospf_neighbor",
vendor_key="zte",
metric_id="ospf_neighbor",
parser_id="ospf_neighbor",
title="OSPF Neighbor",
command_template="show ip ospf neighbor | one-line",
match=r"(?i)^\s*show\s+ip\s+ospf\s+neighbor(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show ip ospf neighbor",
description="OSPF neighbor table (multi Process ID).",
fields=list(_OSPF_FIELDS),
tags=["ospf", "l3", "status"],
sort_order=390,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.vrrp_ipv4",
vendor_key="zte",
metric_id="vrrp",
parser_id="vrrp",
title="VRRP IPv4 Brief",
command_template="show vrrp ipv4 brief | one-line",
match=r"(?i)^\s*show\s+vrrp\s+ipv4\s+brief(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show vrrp ipv4 brief",
description="VRRP IPv4 brief (af=ipv4).",
fields=list(_VRRP_FIELDS),
tags=["vrrp", "l3", "status"],
sort_order=400,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.vrrp_ipv6",
vendor_key="zte",
metric_id="vrrp",
parser_id="vrrp",
title="VRRP IPv6 Brief",
command_template="show vrrp ipv6 brief | one-line",
match=r"(?i)^\s*show\s+vrrp\s+ipv6\s+brief(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show vrrp ipv6 brief",
description="VRRP IPv6 brief (af=ipv6).",
fields=list(_VRRP_FIELDS),
tags=["vrrp", "ipv6", "status"],
sort_order=405,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.optical_brief",
vendor_key="zte",
metric_id="optical_brief",
parser_id="optical_brief",
title="Optical Info Brief",
command_template="show opticalinfo brief | one-line",
match=r"(?i)^\s*show\s+opticalinfo\s+brief(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show opticalinfo brief",
description="Transceiver Rx/Tx power and status.",
fields=list(_OPTICAL_FIELDS),
tags=["optical", "interface", "status"],
sort_order=410,
enabled=True,
kind="collect",
),
# --- Phase 3 BGP neighbor routes ---
ParseProfile(
profile_id="zte.bgp_vpnv4_neighbor_in",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv4 Neighbor In",
command_template="show bgp vpnv4 unicast neighbor in <neighbor>",
match=r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+neighbor\s+in\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv4 unicast neighbor in",
description="Routes learned from VPNv4 neighbor; summary aux for peer state.",
placeholders=[_BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv4", "route"],
sort_order=420,
enabled=True,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv4_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv4_neighbor_out",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv4 Neighbor Out",
command_template="show bgp vpnv4 unicast neighbor out <neighbor>",
match=r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+neighbor\s+out\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv4 unicast neighbor out",
description="Routes advertised to VPNv4 neighbor (large; bind neighbor).",
placeholders=[_BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv4", "route"],
sort_order=425,
enabled=False,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv4_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv6_neighbor_in",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv6 Neighbor In",
command_template="show bgp vpnv6 unicast neighbor in <neighbor>",
match=r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+neighbor\s+in\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv6 unicast neighbor in",
description="Routes learned from VPNv6 neighbor; summary aux for peer state.",
placeholders=[_BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv6", "route"],
sort_order=426,
enabled=True,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv6_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv6_neighbor_out",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv6 Neighbor Out",
command_template="show bgp vpnv6 unicast neighbor out <neighbor>",
match=r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+neighbor\s+out\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp vpnv6 unicast neighbor out",
description="Routes advertised to VPNv6 neighbor (large; bind neighbor).",
placeholders=[_BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv6", "route"],
sort_order=427,
enabled=False,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv6_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv4_vrf_neighbor_in",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv4 VRF Neighbor In",
command_template="show bgp vpnv4 unicast vrf <vrf> neighbor in <neighbor>",
match=(
r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+"
r"neighbor\s+in\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$"
),
textfsm_command="show bgp vpnv4 unicast neighbor in",
description="Per-VRF routes learned from neighbor; VRF summary aux.",
placeholders=[_BGP_VRF_PLACEHOLDER, _BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv4", "vrf", "route"],
sort_order=430,
enabled=True,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv4_vrf_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv4_vrf_neighbor_out",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv4 VRF Neighbor Out",
command_template="show bgp vpnv4 unicast vrf <vrf> neighbor out <neighbor>",
match=(
r"(?i)^\s*show\s+bgp\s+vpnv4\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+"
r"neighbor\s+out\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$"
),
textfsm_command="show bgp vpnv4 unicast neighbor out",
description="Per-VRF routes advertised to neighbor (may be large).",
placeholders=[_BGP_VRF_PLACEHOLDER, _BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv4", "vrf", "route"],
sort_order=435,
enabled=False,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv4_vrf_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv6_vrf_neighbor_in",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv6 VRF Neighbor In",
command_template="show bgp vpnv6 unicast vrf <vrf> neighbor in <neighbor>",
match=(
r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+"
r"neighbor\s+in\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$"
),
textfsm_command="show bgp vpnv6 unicast neighbor in",
description="Per-VRF VPNv6 routes learned from neighbor.",
placeholders=[_BGP_VRF_PLACEHOLDER, _BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv6", "vrf", "route"],
sort_order=440,
enabled=True,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv6_vrf_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
ParseProfile(
profile_id="zte.bgp_vpnv6_vrf_neighbor_out",
vendor_key="zte",
metric_id="bgp_route",
parser_id="bgp_route",
title="BGP VPNv6 VRF Neighbor Out",
command_template="show bgp vpnv6 unicast vrf <vrf> neighbor out <neighbor>",
match=(
r"(?i)^\s*show\s+bgp\s+vpnv6\s+unicast\s+vrf\s+(?P<vrf>\S+)\s+"
r"neighbor\s+out\s+(?P<neighbor>\S+)(?:\s*\|\s*one-line)?\s*$"
),
textfsm_command="show bgp vpnv6 unicast neighbor out",
description="Per-VRF VPNv6 routes advertised to neighbor.",
placeholders=[_BGP_VRF_PLACEHOLDER, _BGP_NEIGHBOR_PLACEHOLDER],
fields=list(_BGP_ROUTE_FIELDS),
tags=["bgp", "vpnv6", "vrf", "route"],
sort_order=445,
enabled=False,
kind="collect",
aux_commands=[AuxCommand(key="bgp_summary", profile_id="zte.bgp_vpnv6_vrf_summary")],
enrich_joins=[
EnrichJoin(
from_aux="bgp_summary",
on="neighbor",
take=("as_num", "state", "pfx_rcd"),
),
],
),
# --- Phase 4 forwarding / L2 ---
ParseProfile(
profile_id="zte.ip_route_vrf",
vendor_key="zte",
metric_id="ip_route",
parser_id="ip_route",
title="IPv4 Forwarding VRF",
command_template="show ip forwarding route vrf <vrf>",
match=r"(?i)^\s*show\s+ip\s+forwarding\s+route\s+vrf\s+(?P<vrf>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show ip forwarding route",
description="IPv4 FIB for one VRF.",
placeholders=[_BGP_VRF_PLACEHOLDER],
fields=list(_IP_ROUTE_FIELDS),
tags=["route", "ipv4", "vrf"],
sort_order=450,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.ip_route",
vendor_key="zte",
metric_id="ip_route",
parser_id="ip_route",
title="IPv4 Forwarding Global",
command_template="show ip forwarding route",
match=r"(?i)^\s*show\s+ip\s+forwarding\s+route(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show ip forwarding route",
description="Global IPv4 FIB (large; disabled by default).",
fields=list(_IP_ROUTE_FIELDS),
tags=["route", "ipv4"],
sort_order=455,
enabled=False,
kind="collect",
),
ParseProfile(
profile_id="zte.ipv6_route_vrf",
vendor_key="zte",
metric_id="ipv6_route",
parser_id="ipv6_route",
title="IPv6 Forwarding VRF",
command_template="show ipv6 forwarding route vrf <vrf>",
match=r"(?i)^\s*show\s+ipv6\s+forwarding\s+route\s+vrf\s+(?P<vrf>\S+)(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show ipv6 forwarding route",
description="IPv6 FIB for one VRF.",
placeholders=[_BGP_VRF_PLACEHOLDER],
fields=list(_IPV6_ROUTE_FIELDS),
tags=["route", "ipv6", "vrf"],
sort_order=460,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.ipv6_route",
vendor_key="zte",
metric_id="ipv6_route",
parser_id="ipv6_route",
title="IPv6 Forwarding Global",
command_template="show ipv6 forwarding route",
match=r"(?i)^\s*show\s+ipv6\s+forwarding\s+route(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show ipv6 forwarding route",
description="Global IPv6 FIB (large; disabled by default).",
fields=list(_IPV6_ROUTE_FIELDS),
tags=["route", "ipv6"],
sort_order=465,
enabled=False,
kind="collect",
),
ParseProfile(
profile_id="zte.l2vpn_pw",
vendor_key="zte",
metric_id="l2vpn_pw",
parser_id="l2vpn_pw",
title="L2VPN PW State",
command_template="show l2vpn forwardinfo | one-line",
match=r"(?i)^\s*show\s+l2vpn\s+forwardinfo(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show l2vpn forwardinfo",
description="L2VPN pseudowire forwardinfo state.",
fields=list(_L2VPN_PW_FIELDS),
tags=["l2vpn", "pw", "status"],
sort_order=470,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.l2vpn_mac",
vendor_key="zte",
metric_id="l2vpn_mac",
parser_id="l2vpn_mac",
title="L2VPN MAC Table",
command_template="show mac l2vpn | one-line",
match=r"(?i)^\s*show\s+mac\s+l2vpn(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show mac l2vpn",
description="L2VPN MAC table (large; disabled by default).",
fields=list(_L2VPN_MAC_FIELDS),
tags=["l2vpn", "mac"],
sort_order=480,
enabled=False,
kind="collect",
),
ParseProfile(
profile_id="zte.evpn_mac",
vendor_key="zte",
metric_id="evpn_mac",
parser_id="evpn_mac",
title="BGP EVPN MAC",
command_template="show bgp evpn mac | one-line",
match=r"(?i)^\s*show\s+bgp\s+evpn\s+mac(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show bgp evpn mac",
description="BGP EVPN MAC NLRI (large; disabled by default).",
fields=list(_EVPN_MAC_FIELDS),
tags=["bgp", "evpn", "mac"],
sort_order=490,
enabled=False,
kind="collect",
),
# --- Config intent (P0) ---
ParseProfile(
profile_id="zte.config_vrf",
vendor_key="zte",
metric_id="config_vrf",
parser_id="config_vrf",
title="Config VRF Intent",
command_template="show running-config vrf",
match=r"(?i)^\s*show\s+running-config\s+vrf(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config vrf",
description="VRF RD/RT/AF intent from running-config vrf (no secrets).",
fields=list(_CONFIG_VRF_FIELDS),
tags=["config", "vrf", "intent"],
sort_order=500,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_interface",
vendor_key="zte",
metric_id="config_interface",
parser_id="config_interface",
title="Config Interface Intent",
command_template="show running-config if-intf",
match=r"(?i)^\s*show\s+running-config\s+if-intf(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config if-intf",
description="Interface VRF/IP/admin intent (richer than if_intf aux map).",
fields=list(_CONFIG_IFACE_FIELDS),
tags=["config", "interface", "intent"],
sort_order=510,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_bgp_peer",
vendor_key="zte",
metric_id="config_bgp_peer",
parser_id="config_bgp_peer",
title="Config BGP Peer Intent",
command_template="show running-config bgp",
match=r"(?i)^\s*show\s+running-config\s+bgp(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config bgp",
description="BGP neighbor AF activate / remote-as intent (passwords skipped).",
fields=list(_CONFIG_BGP_PEER_FIELDS),
tags=["config", "bgp", "intent"],
sort_order=520,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_l2vpn_pw",
vendor_key="zte",
metric_id="config_l2vpn_pw",
parser_id="config_l2vpn_pw",
title="Config L2VPN PW Intent",
command_template="show running-config l2vpn",
match=r"(?i)^\s*show\s+running-config\s+l2vpn(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config l2vpn",
description="VPWS/VPLS pseudo-wire peer/vcid intent.",
fields=list(_CONFIG_L2VPN_PW_FIELDS),
tags=["config", "l2vpn", "intent"],
sort_order=530,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_static_route",
vendor_key="zte",
metric_id="config_static_route",
parser_id="config_static_route",
title="Config Static Route (IPv4)",
command_template="show running-config static",
match=r"(?i)^\s*show\s+running-config\s+static(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config static",
description="IPv4 static route intent from running-config static.",
fields=list(_CONFIG_STATIC_ROUTE_FIELDS),
tags=["config", "static", "route", "intent"],
sort_order=540,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_static_route_v6",
vendor_key="zte",
metric_id="config_static_route",
parser_id="config_static_route",
title="Config Static Route (IPv6)",
command_template="show running-config ipv6-static-route",
match=r"(?i)^\s*show\s+running-config\s+ipv6-static-route(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config ipv6-static-route",
description="IPv6 static route intent from running-config ipv6-static-route.",
fields=list(_CONFIG_STATIC_ROUTE_FIELDS),
tags=["config", "static", "route", "ipv6", "intent"],
sort_order=541,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_ospf",
vendor_key="zte",
metric_id="config_ospf",
parser_id="config_ospf",
title="Config OSPF Intent (v2)",
command_template="show running-config ospfv2",
match=r"(?i)^\s*show\s+running-config\s+ospfv2(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config ospfv2",
description="OSPFv2 process/area/interface intent (auth secrets skipped).",
fields=list(_CONFIG_OSPF_FIELDS),
tags=["config", "ospf", "intent"],
sort_order=550,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_ospf_v3",
vendor_key="zte",
metric_id="config_ospf",
parser_id="config_ospf",
title="Config OSPF Intent (v3)",
command_template="show running-config ospfv3",
match=r"(?i)^\s*show\s+running-config\s+ospfv3(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config ospfv3",
description="OSPFv3 process/area/interface intent.",
fields=list(_CONFIG_OSPF_FIELDS),
tags=["config", "ospf", "ipv6", "intent"],
sort_order=551,
enabled=True,
kind="collect",
),
ParseProfile(
profile_id="zte.config_isis",
vendor_key="zte",
metric_id="config_isis",
parser_id="config_isis",
title="Config ISIS Intent",
command_template="show running-config isis",
match=r"(?i)^\s*show\s+running-config\s+isis(?:\s*\|\s*one-line)?\s*$",
textfsm_command="show running-config isis",
description="IS-IS process/interface intent (auth secrets skipped).",
fields=list(_CONFIG_ISIS_FIELDS),
tags=["config", "isis", "intent"],
sort_order=560,
enabled=True,
kind="collect",
),
]