feat: set up SNMP with net-snmp
CI / test (3.10) (pull_request) Successful in 30s
CI / test (3.11) (pull_request) Successful in 32s
CI / test (3.12) (pull_request) Successful in 36s
CI / test (3.10) (push) Successful in 45s
CI / test (3.11) (push) Successful in 30s
CI / test (3.12) (push) Successful in 29s

run_device_action("fix_snmp") and get_snmp_config for both drivers, as
decided in NetOrk/netork#800: net-snmp from packages rather than the base
daemons, because it answers UCD-SNMP-MIB, which netOrk's health metrics
read.

- fix_snmp installs net-snmp, writes the configuration netOrk uses on
  Linux (v2c, community "public", agentAddress udp:161) through stdin as
  root, enables and restarts the agent (FreeBSD `service snmpd`, OpenBSD
  `rcctl ... netsnmpd`, as `snmpd` is OpenBSD's own daemon) and asks it
  for sysDescr. It stops at the first step that fails and says why.
- get_snmp_config reports a running net-snmp's community and port.
- FreeBSD's install_package bootstraps pkg on a classic system that never
  had it instead of waiting for an answer that never comes.

Checked live: FreeBSD from a bare system, OpenBSD again over an existing
setup. Memory, swap and load answer on both; FreeBSD's ssCpuIdle about a
minute after start; OpenBSD's CPU figures from net-snmp are wrong (#800).
This commit is contained in:
2026-10-08 10:05:09 +02:00
parent 7bf028ef4d
commit aef58ca161
6 changed files with 190 additions and 4 deletions
+97 -2
View File
@@ -274,7 +274,11 @@ class TestPackages:
@pytest.mark.parametrize(
("cls", "install", "uninstall"),
[
(FreeBSDDriver, "pkg install -y nginx", "pkg delete -y nginx"),
(
FreeBSDDriver,
"env ASSUME_ALWAYS_YES=yes pkg install -y nginx",
"pkg delete -y nginx",
),
(OpenBSDDriver, "pkg_add -I nginx", "pkg_delete nginx"),
],
)
@@ -287,7 +291,7 @@ class TestPackages:
def test_a_version_is_part_of_the_name(self):
driver = _channel(FreeBSDDriver, {})
driver.install_package("nginx", "1.28.0")
assert driver.calls == [("pkg install -y nginx-1.28.0", True)]
assert driver.calls == [("env ASSUME_ALWAYS_YES=yes pkg install -y nginx-1.28.0", True)]
def test_a_failed_install_raises(self):
driver = _channel(OpenBSDDriver, {("pkg_add -I nope", True): ("Can't find nope", 1)})
@@ -437,3 +441,94 @@ class TestServices:
with pytest.raises(ValueError):
driver.manage_service(name, action)
assert driver.calls == []
class TestSnmp:
"""net-snmp from packages, as decided in NetOrk/netork#800: UCD-SNMP-MIB,
the same health metrics as on Linux."""
PROBE_OK = "STRING: FreeBSD host 15.1-RELEASE-p4 FreeBSD 15.1-RELEASE-p4 GENERIC amd64"
@pytest.mark.parametrize(
("cls", "install", "conf", "start"),
[
(
FreeBSDDriver,
"env ASSUME_ALWAYS_YES=yes pkg install -y net-snmp",
"/usr/local/etc/snmp/snmpd.conf",
"sysrc snmpd_enable=YES && service snmpd restart",
),
(
OpenBSDDriver,
"pkg_add -I net-snmp",
"/etc/snmp/snmpd.conf",
"rcctl enable netsnmpd && rcctl restart netsnmpd",
),
],
)
def test_fix_snmp_installs_configures_and_starts_net_snmp(self, cls, install, conf, start):
driver = _channel(cls, {BsdDriver.SNMP_PROBE: self.PROBE_OK})
stdin_seen = {}
run = driver.run_command
def recording(command, *, privileged=False, timeout=60, stdin=None):
if stdin is not None:
stdin_seen[command] = stdin
return run(command, privileged=privileged, timeout=timeout, stdin=stdin)
driver.run_command = recording # type: ignore[method-assign]
result = driver.run_device_action("fix_snmp")
assert result["success"] is True
commands = [c for c, _ in driver.calls]
assert commands[0] == install
assert any(conf in c and "cat >" in c for c in commands)
assert start in commands
assert commands[-1] == BsdDriver.SNMP_PROBE
assert all(p for c, p in driver.calls if c != BsdDriver.SNMP_PROBE) # root for the setup
written = next(v for k, v in stdin_seen.items() if conf in k).decode()
assert "agentAddress udp:161" in written and "rocommunity public" in written
def test_a_failed_install_stops_and_says_so(self):
driver = _channel(
FreeBSDDriver,
{
("env ASSUME_ALWAYS_YES=yes pkg install -y net-snmp", True): (
"pkg: No packages available",
1,
)
},
)
result = driver.run_device_action("fix_snmp")
assert result["success"] is False
assert "No packages available" in result["output"]
assert len(driver.calls) == 1
def test_no_answer_from_the_agent_is_a_failure(self):
driver = _channel(
OpenBSDDriver, {BsdDriver.SNMP_PROBE: "Timeout: No Response from 127.0.0.1"}
)
assert driver.run_device_action("fix_snmp")["success"] is False
def test_unknown_action(self):
with pytest.raises(NotImplementedError):
_channel(FreeBSDDriver, {}).run_device_action("fix_apt_proxy")
def test_snmp_config_of_a_running_agent(self):
driver = _channel(
FreeBSDDriver,
{
"pgrep -f /usr/local/sbin/snmpd": "1234",
"cat /usr/local/etc/snmp/snmpd.conf": "agentAddress udp:1161\nrocommunity s3cret\n",
},
)
assert driver.get_snmp_config() == {
"running": True,
"community": "s3cret",
"port": 1161,
"version": "2c",
}
def test_no_agent_running_means_no_config(self):
driver = _channel(OpenBSDDriver, {"pgrep -f /usr/local/sbin/snmpd": ("", 1)})
assert driver.get_snmp_config() is None