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 = []
|
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:
|
try:
|
||||||
result = self._post("/api/core/firmware/install/os-net-snmp")
|
chk = self._get("/api/netsnmp/general/get")
|
||||||
lines.append(f"[install] {result}")
|
plugin_installed = isinstance(chk, dict) and "general" in chk
|
||||||
except Exception as exc:
|
except Exception:
|
||||||
logger.debug("os-net-snmp install skipped or failed: %s", exc)
|
pass
|
||||||
lines.append(f"[install] already installed or skipped")
|
|
||||||
|
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
|
# 2. Configure SNMP
|
||||||
try:
|
try:
|
||||||
@@ -1628,16 +1643,40 @@ class OPNsenseDriver(FirewallDriver):
|
|||||||
logger.debug("Firewall rule for SNMP failed: %s", exc)
|
logger.debug("Firewall rule for SNMP failed: %s", exc)
|
||||||
lines.append(f"[firewall] error: {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:
|
try:
|
||||||
cfg = self._get("/api/netsnmp/general/get")
|
import socket as _socket
|
||||||
general = cfg.get("general", cfg)
|
sock = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM)
|
||||||
success = str(general.get("enabled", "0")) == "1" and bool(general.get("community"))
|
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:
|
except Exception as exc:
|
||||||
logger.debug("SNMP verification failed: %s", exc)
|
logger.debug("SNMP UDP probe failed: %s", exc)
|
||||||
success = False
|
# 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)}
|
return {"success": success, "output": "\n".join(lines)}
|
||||||
|
|
||||||
def get_firewall_aliases(self) -> list[dict[str, Any]]:
|
def get_firewall_aliases(self) -> list[dict[str, Any]]:
|
||||||
|
|||||||
Reference in New Issue
Block a user