mirror of
https://github.com/hansjone/netx.git
synced 2026-10-08 22:20:58 +08:00
Remove fake VRF Route Summary collect item.
Drop the route-summary profiles/parser/persist path; keep VRF list discover for bindings and strip it from default cutover templates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
1642a0adec
commit
a769e603b7
10 changed files with 18 additions and 320 deletions
|
|
@ -24,7 +24,6 @@ from ..models import (
|
|||
BizStateTask,
|
||||
BizStateTaskItem,
|
||||
BizStateTaskItemBinding,
|
||||
BizStateVrfRouteSummary,
|
||||
)
|
||||
from ..ne_netmiko import disable_target_paging, send_show_command
|
||||
from ..ne_session_factory import close_netmiko_connection, open_netmiko_connection
|
||||
|
|
@ -116,45 +115,6 @@ def _persist_lldp_rows(
|
|||
return n
|
||||
|
||||
|
||||
def _persist_vrf_route_summary(
|
||||
db,
|
||||
*,
|
||||
batch: BizStateBatch,
|
||||
cmd_row: BizStateBatchCommand,
|
||||
records: list[dict[str, Any]],
|
||||
) -> int:
|
||||
n = 0
|
||||
seen: set[tuple[str, str]] = set()
|
||||
for rec in records:
|
||||
vrf = str(rec.get("vrf") or "").strip()[:128]
|
||||
source = str(rec.get("source") or "").strip()[:64]
|
||||
if not vrf and not source:
|
||||
continue
|
||||
key = (vrf, source)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
try:
|
||||
networks = int(rec.get("networks") or 0)
|
||||
except (TypeError, ValueError):
|
||||
networks = 0
|
||||
db.add(
|
||||
BizStateVrfRouteSummary(
|
||||
id=uuid4().hex,
|
||||
batch_id=batch.id,
|
||||
batch_command_id=cmd_row.id,
|
||||
task_id=batch.task_id,
|
||||
ne_id=batch.ne_id,
|
||||
vrf=vrf,
|
||||
source=source,
|
||||
networks=networks,
|
||||
collected_at=_utcnow(),
|
||||
)
|
||||
)
|
||||
n += 1
|
||||
return n
|
||||
|
||||
|
||||
_GENERIC_METRICS = {
|
||||
"isis_adjacency",
|
||||
"interface_brief",
|
||||
|
|
@ -636,10 +596,6 @@ def _run_collect_session(
|
|||
n = _persist_lldp_rows(
|
||||
sdb, batch=batch_row, cmd_row=cmd_row, records=records
|
||||
)
|
||||
elif hit.profile.metric_id == "vrf_route_summary":
|
||||
n = _persist_vrf_route_summary(
|
||||
sdb, batch=batch_row, cmd_row=cmd_row, records=records
|
||||
)
|
||||
elif hit.profile.metric_id in _GENERIC_METRICS:
|
||||
n = _persist_metric_rows(
|
||||
sdb,
|
||||
|
|
|
|||
|
|
@ -371,21 +371,6 @@ def _default_lldp_sheet() -> dict[str, Any]:
|
|||
)
|
||||
|
||||
|
||||
def _default_vrf_sheet() -> dict[str, Any]:
|
||||
fields = metric_field_map().get("vrf_route_summary") or []
|
||||
keys = [f.name for f in fields if f.is_key] or ["vrf", "source"]
|
||||
ifaces = [f.name for f in fields if f.is_interface]
|
||||
compare = [f.name for f in fields if not f.is_key and f.role in ("state", "meta", "identity")]
|
||||
if not compare:
|
||||
compare = [n for n in ("networks",) if n not in keys]
|
||||
return _sheet_def(
|
||||
metric_id="vrf_route_summary",
|
||||
key_fields=keys,
|
||||
iface_fields=ifaces,
|
||||
compare_fields=compare,
|
||||
)
|
||||
|
||||
|
||||
def _default_sheet_for_metric(metric_id: str, *, compare_roles: tuple[str, ...] = ("state",)) -> dict[str, Any]:
|
||||
fields = metric_field_map().get(metric_id) or []
|
||||
keys = [f.name for f in fields if f.is_key]
|
||||
|
|
@ -724,20 +709,22 @@ def ensure_default_cutover_template(db: Session) -> BizCompareTemplate:
|
|||
.one_or_none()
|
||||
)
|
||||
if row:
|
||||
# Upgrade legacy single-sheet cutover if needed
|
||||
sheets = template_metrics(row)
|
||||
if len(sheets) < 2:
|
||||
_apply_sheets_to_row(row, [_default_lldp_sheet(), _default_vrf_sheet()])
|
||||
row.note = "Built-in multi-metric cutover template (LLDP + VRF)"
|
||||
cleaned = [s for s in sheets if str(s.get("metric_id") or "") != "vrf_route_summary"]
|
||||
if not cleaned:
|
||||
cleaned = [_default_lldp_sheet()]
|
||||
if cleaned != sheets:
|
||||
_apply_sheets_to_row(row, cleaned)
|
||||
row.note = "Built-in cutover template (LLDP)"
|
||||
row.updated_at = _utcnow()
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return row
|
||||
sheets = [_default_lldp_sheet(), _default_vrf_sheet()]
|
||||
sheets = [_default_lldp_sheet()]
|
||||
row = BizCompareTemplate(
|
||||
id=uuid4().hex,
|
||||
name="Cutover default",
|
||||
note="Built-in multi-metric cutover template (LLDP + VRF)",
|
||||
note="Built-in cutover template (LLDP)",
|
||||
created_at=_utcnow(),
|
||||
updated_at=_utcnow(),
|
||||
)
|
||||
|
|
@ -775,33 +762,6 @@ def ensure_default_lldp_template(db: Session) -> BizCompareTemplate:
|
|||
return row
|
||||
|
||||
|
||||
def ensure_default_vrf_template(db: Session) -> BizCompareTemplate:
|
||||
row = (
|
||||
db.query(BizCompareTemplate)
|
||||
.filter(BizCompareTemplate.name == "VRF route summary default")
|
||||
.one_or_none()
|
||||
)
|
||||
if row:
|
||||
if not template_metrics(row):
|
||||
_apply_sheets_to_row(row, [_default_vrf_sheet()])
|
||||
row.updated_at = _utcnow()
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return row
|
||||
row = BizCompareTemplate(
|
||||
id=uuid4().hex,
|
||||
name="VRF route summary default",
|
||||
note="Built-in template for per-VRF route summary cutover compare",
|
||||
created_at=_utcnow(),
|
||||
updated_at=_utcnow(),
|
||||
)
|
||||
_apply_sheets_to_row(row, [_default_vrf_sheet()])
|
||||
db.add(row)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return row
|
||||
|
||||
|
||||
def ensure_default_zte_status_template(db: Session) -> BizCompareTemplate:
|
||||
name = "ZTE status default"
|
||||
row = db.query(BizCompareTemplate).filter(BizCompareTemplate.name == name).one_or_none()
|
||||
|
|
@ -1202,30 +1162,6 @@ def _load_metric_rows(db: Session, *, batch_id: str, metric_id: str) -> list[dic
|
|||
}
|
||||
for n in rows
|
||||
]
|
||||
if metric_id == "vrf_route_summary":
|
||||
from ..models import BizStateVrfRouteSummary
|
||||
|
||||
rows = (
|
||||
db.query(BizStateVrfRouteSummary)
|
||||
.filter(BizStateVrfRouteSummary.batch_id == batch_id)
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
{
|
||||
"vrf": r.vrf,
|
||||
"source": r.source,
|
||||
"networks": r.networks,
|
||||
"_netx": {
|
||||
"batch_id": batch_id,
|
||||
"batch_command_id": r.batch_command_id or "",
|
||||
"task_id": r.task_id or "",
|
||||
"ne_id": r.ne_id or "",
|
||||
"collected_at": r.collected_at.isoformat() + "Z" if r.collected_at else None,
|
||||
"row_id": r.id,
|
||||
},
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
# Generic tabular metrics (ISIS / interface / ARP / ND6 / BGP …)
|
||||
from ..models import BizStateMetricRow
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ from ...ntc_parse import apply_rules, resolve_cli_platform, rules_for_command
|
|||
from .cisco import PARSERS as _CISCO_PARSERS
|
||||
from .common.lldp_neighbors import normalize_lldp_neighbors
|
||||
from .common.vrf_list import normalize_vrf_list
|
||||
from .common.vrf_route_summary import normalize_vrf_route_summary
|
||||
from .ericsson import PARSERS as _ERICSSON_PARSERS
|
||||
from .h3c import PARSERS as _H3C_PARSERS
|
||||
from .huawei import PARSERS as _HUAWEI_PARSERS
|
||||
|
|
@ -64,7 +63,6 @@ _VENDOR_PARSERS: list[dict[str, NormalizeFn]] = [
|
|||
_REGISTRY: dict[str, NormalizeFn] = {
|
||||
"lldp_neighbors": normalize_lldp_neighbors,
|
||||
"vrf_list": normalize_vrf_list,
|
||||
"vrf_route_summary": normalize_vrf_route_summary,
|
||||
}
|
||||
for _pack in _VENDOR_PARSERS:
|
||||
_REGISTRY.update(_pack)
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
"""Per-VRF route summary counts (multi-vendor line scrape)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
_SOURCE_PATTERNS: list[tuple[str, re.Pattern[str]]] = [
|
||||
("connected", re.compile(r"(?i)^\s*connected\s+(\d+)\s*$")),
|
||||
("static", re.compile(r"(?i)^\s*static\s+(\d+)\s*$")),
|
||||
("local", re.compile(r"(?i)^\s*local\s+(\d+)\s*$")),
|
||||
("ospf", re.compile(r"(?i)^\s*ospf(?:\s+\S+)?\s+(\d+)\s*$")),
|
||||
("isis", re.compile(r"(?i)^\s*isis(?:\s+\S+)?\s+(\d+)\s*$")),
|
||||
("bgp", re.compile(r"(?i)^\s*bgp(?:\s+\S+)?\s+(\d+)\s*$")),
|
||||
("rip", re.compile(r"(?i)^\s*rip(?:\s+\S+)?\s+(\d+)\s*$")),
|
||||
("total", re.compile(r"(?i)^\s*(?:total|totals?)\s+(?:routes?\s+)?(\d+)\s*$")),
|
||||
]
|
||||
|
||||
RULE_KEYS: tuple[str, ...] = ()
|
||||
|
||||
|
||||
def normalize_vrf_route_summary(
|
||||
*,
|
||||
raw_text: str,
|
||||
fsm_tables=None,
|
||||
vendor: str = "",
|
||||
device_type: str = "",
|
||||
command: str = "",
|
||||
params: dict[str, str] | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
_ = (vendor, device_type, command, fsm_tables)
|
||||
vrf = str((params or {}).get("vrf") or (params or {}).get("vrf_name") or "").strip()
|
||||
text = str(raw_text or "")
|
||||
found: dict[str, int] = {}
|
||||
for src, pat in _SOURCE_PATTERNS:
|
||||
for line in text.splitlines():
|
||||
m = pat.match(line.strip())
|
||||
if m:
|
||||
found[src] = int(m.group(1))
|
||||
break
|
||||
|
||||
if not found:
|
||||
n = 0
|
||||
for line in text.splitlines():
|
||||
s = line.strip()
|
||||
if not s or s.startswith("-") or s.lower().startswith(("code", "codes", "gateway", "routing table")):
|
||||
continue
|
||||
if re.match(r"^[A-Z*+]>?\s+\S+", s) or re.match(r"^\S+\s+\d+\.\d+\.\d+\.\d+", s):
|
||||
n += 1
|
||||
if n:
|
||||
found["routes"] = n
|
||||
|
||||
rows: list[dict[str, Any]] = []
|
||||
for src, count in found.items():
|
||||
rows.append({"vrf": vrf[:128], "source": src[:64], "networks": count})
|
||||
if vrf and not rows:
|
||||
rows.append({"vrf": vrf[:128], "source": "empty", "networks": 0})
|
||||
return rows
|
||||
|
||||
normalize_vrf_route_summary.RULE_KEYS = RULE_KEYS
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
"""Compat shim — prefer ``parsers.common.vrf_list`` / ``vrf_route_summary``."""
|
||||
"""Compat shim — prefer ``parsers.common.vrf_list``."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .common.vrf_list import normalize_vrf_list
|
||||
from .common.vrf_route_summary import normalize_vrf_route_summary
|
||||
|
||||
__all__ = ["normalize_vrf_list", "normalize_vrf_route_summary"]
|
||||
__all__ = ["normalize_vrf_list"]
|
||||
|
|
|
|||
|
|
@ -133,15 +133,8 @@ def _lldp_profiles() -> list[ParseProfile]:
|
|||
return out
|
||||
|
||||
|
||||
_VRF_ROUTE_FIELDS: list[FieldDef] = [
|
||||
FieldDef("vrf", length=128, indexed=True, is_key=True, display_name="VRF", from_command_param=True),
|
||||
FieldDef("source", length=64, indexed=True, is_key=True, display_name="路由来源"),
|
||||
FieldDef("networks", dtype="int", role="state", display_name="路由条数"),
|
||||
]
|
||||
|
||||
|
||||
def _vrf_profiles() -> list[ParseProfile]:
|
||||
"""Discover VRF list + parameterized route-summary collect (Phase3)."""
|
||||
"""Discover VRF list for parameterized collect bindings (e.g. BGP VRF)."""
|
||||
discover_cmds: dict[str, tuple[str, str, str]] = {
|
||||
# vendor_key: (command, match, textfsm_command)
|
||||
"cisco": ("show vrf", r"(?i)^\s*show\s+vrf\s*$", "show vrf"),
|
||||
|
|
@ -161,24 +154,6 @@ def _vrf_profiles() -> list[ParseProfile]:
|
|||
"show ip vrf",
|
||||
),
|
||||
}
|
||||
collect_cmds: dict[str, tuple[str, str]] = {
|
||||
"cisco": (
|
||||
"show ip route vrf <vrf> summary",
|
||||
r"(?i)^\s*show\s+ip\s+route\s+vrf\s+(?P<vrf>\S+)\s+summary\s*$",
|
||||
),
|
||||
"huawei": (
|
||||
"display ip routing-table vpn-instance <vrf> statistics",
|
||||
r"(?i)^\s*display\s+ip\s+routing-table\s+vpn-instance\s+(?P<vrf>\S+)\s+statistics\s*$",
|
||||
),
|
||||
"h3c": (
|
||||
"display ip routing-table vpn-instance <vrf> statistics",
|
||||
r"(?i)^\s*display\s+ip\s+routing-table\s+vpn-instance\s+(?P<vrf>\S+)\s+statistics\s*$",
|
||||
),
|
||||
"zte": (
|
||||
"show ip route vrf <vrf> summary",
|
||||
r"(?i)^\s*show\s+ip\s+route\s+vrf\s+(?P<vrf>\S+)\s+summary\s*$",
|
||||
),
|
||||
}
|
||||
out: list[ParseProfile] = []
|
||||
order = 200
|
||||
for key, (cmd, match, fsm_cmd) in discover_cmds.items():
|
||||
|
|
@ -207,40 +182,6 @@ def _vrf_profiles() -> list[ParseProfile]:
|
|||
)
|
||||
)
|
||||
order += 5
|
||||
|
||||
order = 220
|
||||
for key, (tmpl, match) in collect_cmds.items():
|
||||
disc_id = f"{key}.vrf_list"
|
||||
out.append(
|
||||
ParseProfile(
|
||||
profile_id=f"{key}.route_vrf_summary",
|
||||
vendor_key=key,
|
||||
metric_id="vrf_route_summary",
|
||||
parser_id="vrf_route_summary",
|
||||
title="VRF Route Summary",
|
||||
command_template=tmpl,
|
||||
match=match,
|
||||
textfsm_command="",
|
||||
description="Per-VRF route source counts (discover VRF → select bindings → collect).",
|
||||
placeholders=[
|
||||
PlaceholderDef(
|
||||
name="vrf",
|
||||
schema_field="vrf",
|
||||
required=True,
|
||||
bind_mode="discover_select",
|
||||
discover_profile_id=disc_id,
|
||||
discover_value_field="vrf_name",
|
||||
discover_label_field="vrf_name",
|
||||
)
|
||||
],
|
||||
fields=list(_VRF_ROUTE_FIELDS),
|
||||
tags=["vrf", "route", "l3"],
|
||||
sort_order=order,
|
||||
enabled=True,
|
||||
kind="collect",
|
||||
)
|
||||
)
|
||||
order += 5
|
||||
return out
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ from ..models import (
|
|||
BizStateTask,
|
||||
BizStateTaskItem,
|
||||
BizStateTaskItemBinding,
|
||||
BizStateVrfRouteSummary,
|
||||
ManagedNE,
|
||||
)
|
||||
from ..timeutil import utcnow_naive
|
||||
|
|
@ -557,13 +556,6 @@ def get_batch(db: Session, batch_id: str) -> dict[str, Any]:
|
|||
.limit(5000)
|
||||
.all()
|
||||
)
|
||||
vrf_rows = (
|
||||
db.query(BizStateVrfRouteSummary)
|
||||
.filter(BizStateVrfRouteSummary.batch_id == batch_id)
|
||||
.order_by(BizStateVrfRouteSummary.vrf.asc(), BizStateVrfRouteSummary.source.asc())
|
||||
.limit(5000)
|
||||
.all()
|
||||
)
|
||||
metric_rows = (
|
||||
db.query(BizStateMetricRow)
|
||||
.filter(BizStateMetricRow.batch_id == batch_id)
|
||||
|
|
@ -620,9 +612,6 @@ def get_batch(db: Session, batch_id: str) -> dict[str, Any]:
|
|||
}
|
||||
for n in neighbors
|
||||
],
|
||||
"vrf_route_summary": [
|
||||
{"vrf": r.vrf, "source": r.source, "networks": r.networks} for r in vrf_rows
|
||||
],
|
||||
"metrics": metrics_by_id,
|
||||
}
|
||||
|
||||
|
|
@ -707,13 +696,6 @@ def export_batch_zip(db: Session, batch_id: str) -> bytes:
|
|||
)
|
||||
zf.writestr("tables/lldp_neighbor.csv", "\n".join(csv_lines) + "\n")
|
||||
|
||||
vrf_csv = ["vrf,source,networks"]
|
||||
for r in detail.get("vrf_route_summary") or []:
|
||||
vrf_csv.append(
|
||||
",".join([_csv(r["vrf"]), _csv(r["source"]), _csv(str(r["networks"]))])
|
||||
)
|
||||
zf.writestr("tables/vrf_route_summary.csv", "\n".join(vrf_csv) + "\n")
|
||||
|
||||
for mid, rows in sorted((detail.get("metrics") or {}).items()):
|
||||
if not rows:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
"""Unit tests for Phase3 VRF binding expand / route summary parse."""
|
||||
"""Unit tests for VRF list discover profiles."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from netx_api.biz_state.command_match import expand_from_bindings, match_command, preview_task_item
|
||||
from netx_api.biz_state.parsers.vrf import normalize_vrf_list, normalize_vrf_route_summary
|
||||
from netx_api.biz_state.parsers.vrf import normalize_vrf_list
|
||||
from netx_api.biz_state.profiles import get_profile, profiles_for_vendor, reload_profiles
|
||||
|
||||
|
||||
|
|
@ -13,60 +12,12 @@ class BizStateVrfTests(unittest.TestCase):
|
|||
def setUp(self) -> None:
|
||||
reload_profiles()
|
||||
|
||||
def test_vrf_profiles_registered(self) -> None:
|
||||
def test_vrf_list_profiles_registered(self) -> None:
|
||||
cisco = profiles_for_vendor("cisco")
|
||||
self.assertTrue(any(p.profile_id == "cisco.vrf_list" and p.kind == "discover" for p in cisco))
|
||||
self.assertTrue(any(p.profile_id == "cisco.route_vrf_summary" for p in cisco))
|
||||
|
||||
def test_expand_multi_vrf_bindings(self) -> None:
|
||||
p = get_profile("cisco.route_vrf_summary")
|
||||
assert p is not None
|
||||
pairs = expand_from_bindings(
|
||||
profile=p,
|
||||
bindings=[
|
||||
{"placeholder": "vrf", "value": "CUST_A"},
|
||||
{"placeholder": "vrf", "value": "CUST_B"},
|
||||
],
|
||||
)
|
||||
self.assertEqual(len(pairs), 2)
|
||||
self.assertEqual(pairs[0][0], "show ip route vrf CUST_A summary")
|
||||
self.assertEqual(pairs[1][0], "show ip route vrf CUST_B summary")
|
||||
hit = match_command(vendor_key="cisco", command=pairs[0][0])
|
||||
self.assertIsNotNone(hit)
|
||||
assert hit is not None
|
||||
self.assertEqual(hit.params.get("vrf"), "CUST_A")
|
||||
|
||||
def test_expand_requires_bindings(self) -> None:
|
||||
p = get_profile("zte.route_vrf_summary")
|
||||
assert p is not None
|
||||
with self.assertRaises(ValueError):
|
||||
expand_from_bindings(profile=p, bindings=[])
|
||||
|
||||
def test_preview_with_bindings(self) -> None:
|
||||
prev = preview_task_item(
|
||||
vendor_key="huawei",
|
||||
profile_id="huawei.route_vrf_summary",
|
||||
bindings=[{"vrf": "VPN1"}],
|
||||
)
|
||||
self.assertTrue(prev["ok"])
|
||||
self.assertEqual(len(prev["commands"]), 1)
|
||||
self.assertIn("VPN1", prev["commands"][0]["command"])
|
||||
|
||||
def test_route_summary_parser(self) -> None:
|
||||
raw = """
|
||||
IP routing table name is CUST_A
|
||||
Route Source Networks
|
||||
connected 3
|
||||
static 1
|
||||
bgp 65001 42
|
||||
Total 46
|
||||
"""
|
||||
rows = normalize_vrf_route_summary(raw_text=raw, params={"vrf": "CUST_A"})
|
||||
by_src = {r["source"]: r["networks"] for r in rows}
|
||||
self.assertEqual(by_src["connected"], 3)
|
||||
self.assertEqual(by_src["bgp"], 42)
|
||||
self.assertEqual(by_src["total"], 46)
|
||||
self.assertTrue(all(r["vrf"] == "CUST_A" for r in rows))
|
||||
self.assertFalse(any(p.metric_id == "vrf_route_summary" for p in cisco))
|
||||
self.assertIsNone(get_profile("cisco.route_vrf_summary"))
|
||||
self.assertIsNone(get_profile("zte.route_vrf_summary"))
|
||||
|
||||
def test_vrf_list_fallback(self) -> None:
|
||||
raw = "CUST_A 100:1 ipv4\nCUST_B 100:2 ipv4\n"
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ src/
|
|||
- Phase1:LLDP 邻居快照;建任务默认启用对应厂商 LLDP profile;支持自定义只采不解析行
|
||||
- Phase2:比对模板(多监控表 / Key·接口·比对字段;空比对=仅条目)、端口映射、CompareJob 列表与详情、先选批次再按 Excel sheet 看 pre/post、`/network/tasks/biz-compare`
|
||||
- API 补充:`GET /v1/biz-state/compare/metrics`;模板 `metrics[]` 多表结构
|
||||
- Phase3:VRF 发现→人选关联→带参采集(`*.route_vrf_summary`);`PUT …/items/{id}/bindings`
|
||||
- Phase3:VRF 发现(`*.vrf_list`)供带参采集绑定;`PUT …/items/{id}/bindings`
|
||||
- 调度:`NETX_BIZ_STATE_SCHEDULER_ENABLED`(默认开),tick `NETX_BIZ_STATE_SCHEDULER_TICK_SEC`
|
||||
- 前端:`/network/tasks/biz-state`(勾选监控项 / 发现 VRF / 批次 / 导出 zip)
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ function columnsFromRows(rows: Record<string, unknown>[]): SheetCol[] {
|
|||
function metricSheetTitle(metricId: string, t: (k: string) => string): string {
|
||||
const map: Record<string, string> = {
|
||||
lldp_neighbor: t("bizState.sheetLldp"),
|
||||
vrf_route_summary: t("bizState.sheetVrfRoute"),
|
||||
isis_adjacency: t("bizState.sheetIsis"),
|
||||
interface_brief: t("bizState.sheetIfaceBrief"),
|
||||
arp: t("bizState.sheetArp"),
|
||||
|
|
@ -174,9 +173,6 @@ function rowsForMetric(batch: any, metricId: string): Record<string, unknown>[]
|
|||
if (mid === "lldp_neighbor") {
|
||||
return ((batch?.lldp_neighbors || []) as Record<string, unknown>[]) || [];
|
||||
}
|
||||
if (mid === "vrf_route_summary") {
|
||||
return ((batch?.vrf_route_summary || []) as Record<string, unknown>[]) || [];
|
||||
}
|
||||
return Array.isArray(fromGeneric) ? (fromGeneric as Record<string, unknown>[]) : [];
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +211,6 @@ function buildBatchSheets(batch: any, t: (k: string) => string): SheetDef[] {
|
|||
for (const c of cmds) pushMid(String(c.metric_id || ""));
|
||||
for (const mid of Object.keys(batch?.metrics || {})) pushMid(mid);
|
||||
if ((batch?.lldp_neighbors || []).length) pushMid("lldp_neighbor");
|
||||
if ((batch?.vrf_route_summary || []).length) pushMid("vrf_route_summary");
|
||||
|
||||
for (const mid of metricOrder) {
|
||||
const rows = rowsForMetric(batch, mid);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue