fix: _action_fix_snmp skips reinstall if plugin already present
Calling firmware/install on an already-installed os-net-snmp plugin triggers an async reinstall that overwrites the config with factory defaults a few minutes later — causing SNMP to stop working again. Now checks /api/netsnmp/general/get first and only installs if the plugin is genuinely absent. Also adds a lightweight UDP/161 probe to verify SNMP is actually reachable after the fix (falls back to API config check if the socket probe is unavailable). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8e413e4c60
commit
9f9fafb6f5
+52
-13
@@ -1555,13 +1555,28 @@ class OPNsenseDriver(FirewallDriver):
|
||||
"""
|
||||
lines: list = []
|
||||
|
||||
# 1. Install os-net-snmp plugin
|
||||
# 1. Install os-net-snmp plugin ONLY if not already present.
|
||||
# Calling firmware/install on an already-installed plugin triggers an
|
||||
# async reinstall that overwrites the config with factory defaults a few
|
||||
# minutes later — causing SNMP to stop working again after the fix.
|
||||
plugin_installed = False
|
||||
try:
|
||||
result = self._post("/api/core/firmware/install/os-net-snmp")
|
||||
lines.append(f"[install] {result}")
|
||||
except Exception as exc:
|
||||
logger.debug("os-net-snmp install skipped or failed: %s", exc)
|
||||
lines.append(f"[install] already installed or skipped")
|
||||
chk = self._get("/api/netsnmp/general/get")
|
||||
plugin_installed = isinstance(chk, dict) and "general" in chk
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not plugin_installed:
|
||||
try:
|
||||
result = self._post("/api/core/firmware/install/os-net-snmp")
|
||||
lines.append(f"[install] {result}")
|
||||
import time as _time
|
||||
_time.sleep(5) # wait for install to settle
|
||||
except Exception as exc:
|
||||
logger.debug("os-net-snmp install failed: %s", exc)
|
||||
lines.append(f"[install] failed: {exc}")
|
||||
else:
|
||||
lines.append("[install] os-net-snmp already installed — skipping reinstall")
|
||||
|
||||
# 2. Configure SNMP
|
||||
try:
|
||||
@@ -1628,16 +1643,40 @@ class OPNsenseDriver(FirewallDriver):
|
||||
logger.debug("Firewall rule for SNMP failed: %s", exc)
|
||||
lines.append(f"[firewall] error: {exc}")
|
||||
|
||||
# 5. Verify SNMP config
|
||||
# 5. Verify — try actual UDP/161 probe first, fall back to API config check
|
||||
success = False
|
||||
try:
|
||||
cfg = self._get("/api/netsnmp/general/get")
|
||||
general = cfg.get("general", cfg)
|
||||
success = str(general.get("enabled", "0")) == "1" and bool(general.get("community"))
|
||||
import socket as _socket
|
||||
sock = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
|
||||
sock.settimeout(3)
|
||||
community = b"public"
|
||||
# Minimal SNMPv2c GetRequest for sysDescr
|
||||
pdu = (b"\x30\x26\x02\x01\x01\x04"
|
||||
+ bytes([len(community)]) + community
|
||||
+ b"\xa0\x19\x02\x04\x00\x00\x00\x01"
|
||||
+ b"\x02\x01\x00\x02\x01\x00"
|
||||
+ b"\x30\x0b\x30\x09\x06\x05\x2b\x06\x01\x02\x01\x05\x00")
|
||||
sock.sendto(pdu, (self.hostname, 161))
|
||||
try:
|
||||
data, _ = sock.recvfrom(1024)
|
||||
success = len(data) > 0
|
||||
lines.append("[ok] SNMP UDP probe successful.")
|
||||
except _socket.timeout:
|
||||
lines.append("[warn] SNMP UDP probe timed out — service may be starting.")
|
||||
finally:
|
||||
sock.close()
|
||||
except Exception as exc:
|
||||
logger.debug("SNMP verification failed: %s", exc)
|
||||
success = False
|
||||
logger.debug("SNMP UDP probe failed: %s", exc)
|
||||
# Fall back to API config check
|
||||
try:
|
||||
cfg = self._get("/api/netsnmp/general/get")
|
||||
general = cfg.get("general", cfg)
|
||||
success = str(general.get("enabled", "0")) == "1" and bool(general.get("community"))
|
||||
lines.append("[ok] SNMP config active (UDP probe unavailable)." if success
|
||||
else "[warn] SNMP config check failed.")
|
||||
except Exception:
|
||||
lines.append("[warn] Could not verify SNMP state.")
|
||||
|
||||
lines.append("[ok] SNMP active." if success else "[warn] Could not verify SNMP state.")
|
||||
return {"success": success, "output": "\n".join(lines)}
|
||||
|
||||
def get_firewall_aliases(self) -> list[dict[str, Any]]:
|
||||
|
||||
Reference in New Issue
Block a user