diff --git a/napalm_procurve/procurve.py b/napalm_procurve/procurve.py index 8db1977..e68dcef 100644 --- a/napalm_procurve/procurve.py +++ b/napalm_procurve/procurve.py @@ -994,6 +994,101 @@ class ProcurveDriver(SwitchDriver): """Return True if a candidate config is loaded.""" return self._candidate_config is not None + # ── SNMP / Health ────────────────────────────────────────────────────────── + + def get_device_warnings(self) -> list: + """Return device warnings. SNMP detection handled by poll task.""" + return [] + + def get_snmp_config(self): + """Return SNMP config if a community is configured on the switch.""" + try: + from napalm_device_types.models import SNMPConfigDict + except ImportError: + return None + + # Use a single command with short read_timeout to avoid blocking the poll. + try: + out = self._device.send_command( + "show snmp-server", + expect_string=rf"{re.escape(self._device.base_prompt)}[>#]", + read_timeout=10, + ).strip() if self._device else "" + except Exception: + return None + if not out: + return None + + # Parse communities from output + community = None + for line in out.splitlines(): + m = re.match(r"\s+(\S+)\s+(Manager|Operator)\s+(Restricted|Unrestricted)", line, re.I) + if m: + comm = m.group(1) + access = m.group(3).lower() + if access == "restricted": # read-only — prefer this + community = comm + break + elif community is None: + community = comm # fallback to first found + + if not community: + return None + + return SNMPConfigDict(running=True, community=community, port=161, version="2c") + + 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]: + """Find the VLAN that carries this switch's management IP.""" + try: + out = self._send_command("show ip") + for line in out.splitlines(): + # " VLAN8 | 172.22.8.x ..." or similar + m = re.search(r"VLAN\s*(\d+)[^|]*\|\s*" + re.escape(self.hostname), line, re.I) + if m: + return int(m.group(1)) + # Alternative: "VLAN 8 172.22.8.x" + m2 = re.search(r"\bVLAN\s+(\d+)\b.*\b" + re.escape(self.hostname) + r"\b", line, re.I) + if m2: + return int(m2.group(1)) + except Exception: + pass + return None + + def _action_fix_snmp(self) -> Dict: + """Enable SNMP with community 'public' (read-only) on the ProCurve switch. + + ProCurve/Aruba syntax: + snmp-server community "public" manager restricted + """ + lines: list = [] + + self._enter_config_mode() + + # Enable SNMP with read-only community 'public' + # ProCurve: manager = standard access level, restricted = read-only + self._send_command('snmp-server community "public" manager restricted') + lines.append("[config] SNMP community 'public' (manager restricted / read-only) configured.") + + self._exit_config_mode() + self._save_config() + lines.append("[config] Configuration saved.") + + # Verify + out = self._send_command("show snmp-server") + success = "public" in out + if success: + lines.append("[ok] SNMP is active with community 'public'.") + else: + lines.append(f"[warn] Verification — community not found: {out[:200]}") + + return {"success": success, "output": "\n".join(lines)} + # --------------------------------------------------------------------------- # Helpers