From cbe73cab64ceb2c636ff353d62c14bdd753a8856 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Mon, 1 Jun 2026 13:09:45 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20SNMP=20support=20=E2=80=94=20get=5Fsnmp?= =?UTF-8?q?=5Fconfig(),=20fix=5Fsnmp=20action,=20get=5Fdevice=5Fwarnings()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_snmp_config() reads 'show snmp community', fix_snmp detects management VLAN from 'show ip interface' and configures source-interface + community with correct JetStream CLI syntax. get_device_warnings() added (was missing, caused AttributeError). Co-Authored-By: Claude Sonnet 4.6 --- napalm_tplink_jetstream/tplink_jetstream.py | 109 ++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/napalm_tplink_jetstream/tplink_jetstream.py b/napalm_tplink_jetstream/tplink_jetstream.py index d55da50..9f4af01 100644 --- a/napalm_tplink_jetstream/tplink_jetstream.py +++ b/napalm_tplink_jetstream/tplink_jetstream.py @@ -1740,3 +1740,112 @@ class TPLinkJetstreamDriver(SwitchDriver): for cmd in commands: result[cmd] = self._send_command(cmd) return result + + # ── SNMP / Health ────────────────────────────────────────────────────────── + + def get_snmp_config(self): + """Return SNMP agent config if SNMP is enabled on the switch. + + TP-Link JetStream switches have SNMP built-in — no daemon to install. + Reads community from 'show snmp community'. + """ + try: + from napalm_device_types.models import SNMPConfigDict + except ImportError: + return None + + out = self._send_command("show snmp community") + if not out or "disabled" in out.lower(): + return None + + # Parse first read-only community + community = "public" + in_table = False + for line in out.splitlines(): + line_s = line.strip() + if re.match(r"^-{4,}", line_s): + in_table = True + continue + if not in_table or not line_s: + continue + parts = line_s.split() + if len(parts) >= 2: + community = parts[0] + break + + return SNMPConfigDict(running=True, community=community, port=161, version="2c") + + + def get_device_warnings(self) -> list: + """Return device warnings. Currently delegates to SNMP detection only.""" + return [] + + def run_device_action(self, action: str) -> Dict: + """Execute a named action on the switch.""" + if action == "fix_snmp": + return self._action_fix_snmp() + raise NotImplementedError(f"Unknown action: {action!r}") + + def _detect_management_vlan(self) -> Optional[int]: + """Detect which VLAN interface carries the management IP (self.hostname).""" + try: + out = self._send_command("show ip interface") + import re as _re + # Match "VLAN is up" followed by IP line containing self.hostname + vlan = None + current_vlan = None + for line in out.splitlines(): + m = _re.match(r"VLAN(\d+)\s+is", line, _re.IGNORECASE) + if m: + current_vlan = int(m.group(1)) + if current_vlan and self.hostname in line and "IP address" in line: + vlan = current_vlan + break + return vlan + except Exception: + return None + + def _action_fix_snmp(self) -> Dict: + """Enable SNMP and configure community 'public' on the switch. + + TP-Link JetStream uses CLI commands — SNMP is built-in, no install needed. + Also sets snmp-server source-interface to the management VLAN so that + SNMP responses are sent from the correct interface. + """ + lines: list = [] + + # Detect management VLAN (the VLAN interface carrying this device's IP) + mgmt_vlan = self._detect_management_vlan() + if mgmt_vlan: + lines.append(f"[detect] Management VLAN: {mgmt_vlan}") + else: + lines.append("[detect] Could not auto-detect management VLAN.") + + # Configure SNMP in config mode + self._enter_config_mode() + self._send_command("snmp-server") + lines.append("[config] SNMP enabled.") + + # Community: TP-Link syntax is snmp-server community "" read-only "" + self._send_command('snmp-server community "public" read-only "viewDefault"') + lines.append("[config] Community 'public' (read-only, viewDefault) configured.") + + # Set source-interface so responses come from the management VLAN + if mgmt_vlan: + self._send_command(f"snmp-server source-interface vlan {mgmt_vlan}") + lines.append(f"[config] Source-interface set to vlan {mgmt_vlan}.") + + # Exit config mode and save + self._exit_config_mode() + self._save_config() + lines.append("[config] Configuration saved.") + + # Verify + out = self._send_command("show snmp community") + success = "public" in out and "disabled" not in out.lower() + if success: + lines.append("[ok] SNMP is active with community 'public'.") + else: + lines.append(f"[warn] Verification failed: {out[:100]}") + + return {"success": success, "output": "\n".join(lines)}