From ed11f5a60c23fb5f0edcf2ae6142b15f72ebd79b Mon Sep 17 00:00:00 2001 From: oliver Date: Sun, 20 Sep 2026 19:26:31 +0800 Subject: [PATCH] Split L2VPN service instance into type (VPLS/VPWS) and name fields. Co-authored-by: Cursor --- .../biz_state/parsers/zte/l2vpn_pw_detail.py | 16 +++++++++++++++- netx_api/biz_state/profiles.py | 1 + tests/test_zte_extended_parsers.py | 8 +++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/netx_api/biz_state/parsers/zte/l2vpn_pw_detail.py b/netx_api/biz_state/parsers/zte/l2vpn_pw_detail.py index aed71f9..c3634c7 100644 --- a/netx_api/biz_state/parsers/zte/l2vpn_pw_detail.py +++ b/netx_api/biz_state/parsers/zte/l2vpn_pw_detail.py @@ -12,6 +12,7 @@ from ..common.pipeline import prefer_fsm RULE_KEYS = ("zte_zxros_show_l2vpn_forwardinfo_detail",) _SERVICE_RE = re.compile(r"^Service type and instance name:\[([^\]]+)\]\s*$", re.I) +_SERVICE_SPLIT_RE = re.compile(r"^(VPLS|VPWS)\s+(.+)$", re.I) # Two-column "Label : value Label : value" or single "Label : value" _KV_PAIR_RE = re.compile( r"([A-Za-z][A-Za-z0-9 /|_.-]*)\s*:\s*" @@ -78,12 +79,25 @@ def _empty() -> dict[str, str]: } +def _split_service(raw: str) -> tuple[str, str]: + """Split ``VPLS foo`` / ``VPWS bar`` into (type, instance name).""" + text = str(raw or "").strip() + if not text: + return "", "" + m = _SERVICE_SPLIT_RE.match(text) + if m: + return m.group(1).upper(), m.group(2).strip() + return "", text + + def _row_out(cur: dict[str, str]) -> dict[str, Any] | None: pw = str(cur.get("pw_name") or "").strip() if not pw: return None + svc_type, svc_name = _split_service(str(cur.get("service_instance") or "")) return { - "service_instance": str(cur.get("service_instance") or "")[:256], + "service_instance_type": svc_type[:32], + "service_instance": svc_name[:256], "pw_name": pw[:128], "peer": str(cur.get("peer") or "")[:64], "vcid": str(cur.get("vcid") or "")[:64], diff --git a/netx_api/biz_state/profiles.py b/netx_api/biz_state/profiles.py index b9d743e..237cd97 100644 --- a/netx_api/biz_state/profiles.py +++ b/netx_api/biz_state/profiles.py @@ -382,6 +382,7 @@ _L2VPN_PW_DETAIL_FIELDS: list[FieldDef] = [ FieldDef("vc_status", length=32, role="state", display_name="VC Status"), FieldDef("remote_status", length=32, role="state", display_name="Remote"), FieldDef("activation_status", length=32, role="state", display_name="Activation"), + FieldDef("service_instance_type", length=32, role="meta", display_name="Service Type"), FieldDef("service_instance", length=256, role="meta", display_name="Service"), FieldDef("conn_mode", length=32, role="meta", display_name="Mode"), FieldDef("signaling", length=32, role="meta", display_name="Signaling"), diff --git a/tests/test_zte_extended_parsers.py b/tests/test_zte_extended_parsers.py index 2fb6c97..9596cbc 100644 --- a/tests/test_zte_extended_parsers.py +++ b/tests/test_zte_extended_parsers.py @@ -341,7 +341,10 @@ class ZteExtendedParserTests(unittest.TestCase): self.assertEqual(by["pw19001"]["remote_status"], "ALLOK") self.assertEqual(by["pw19001"]["vcid"], "19001") self.assertEqual(by["pw19001"]["peer"], "10.0.0.6") - self.assertIn("demo-vpls-1", by["pw19001"]["service_instance"]) + self.assertEqual(by["pw19001"]["service_instance_type"], "VPLS") + self.assertEqual(by["pw19001"]["service_instance"], "qualified demo-vpls-1") + self.assertEqual(by["pw19011"]["service_instance_type"], "VPLS") + self.assertEqual(by["pw19011"]["service_instance"], "demo-vpls-2") self.assertEqual(by["pw19011"]["vc_status"].upper(), "DOWN") self.assertEqual(by["pw19011"]["vccv_cv"], "LSP|BFD_BASIC_HEAD") @@ -377,7 +380,10 @@ class ZteExtendedParserTests(unittest.TestCase): ) self.assertEqual(len(rows), 6) self.assertTrue(all(r["vc_status"].upper() == "UP" for r in rows)) + self.assertTrue(all(r["service_instance_type"] == "VPLS" for r in rows)) self.assertEqual(rows[0]["pw_name"], "pw19001") + self.assertEqual(rows[0]["service_instance"], "qualified mxy-martini-vpls-1") + self.assertEqual(rows[2]["service_instance"], "VPLS_4202") self.assertEqual(rows[-1]["pw_name"], "pw1230002") def test_profiles_and_expand(self) -> None: