feat: SNMP support — get_snmp_config(), fix_snmp action, get_device_warnings()
get_snmp_config() uses single 'show snmp-server' command with read_timeout=10 to avoid blocking the poll. fix_snmp configures 'snmp-server community public manager restricted'. get_device_warnings() added (was missing, caused AttributeError). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e7d054ea2a
commit
5f780190c7
@@ -994,6 +994,101 @@ class ProcurveDriver(SwitchDriver):
|
|||||||
"""Return True if a candidate config is loaded."""
|
"""Return True if a candidate config is loaded."""
|
||||||
return self._candidate_config is not None
|
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
|
# Helpers
|
||||||
|
|||||||
Reference in New Issue
Block a user