feat: read the node's listening sockets through napalm-device-types #11

Merged
christianmanivong merged 1 commits from feat/listening-sockets into master 2026-10-06 16:20:13 +00:00
4 changed files with 49 additions and 1 deletions
+2
View File
@@ -39,6 +39,7 @@ from napalm_device_types import (
HostStatusMixin,
HypervisorDriver,
KernelFactsMixin,
ListeningSocketsMixin,
PortSpec,
SystemdServicesMixin,
)
@@ -84,6 +85,7 @@ class ProxmoxDriver(
ProxmoxRoutingMixin,
ProxmoxSystemMixin,
KernelFactsMixin,
ListeningSocketsMixin,
SystemdServicesMixin,
HostStatusMixin,
HypervisorDriver,
+9
View File
@@ -231,6 +231,15 @@ class ProxmoxSystemMixin:
"""The transport for ``KernelFactsMixin.get_kernel_facts``: the exec path."""
return self._exec_ssh_command(command)
# ------------------------------------------------------------------ #
# Listening sockets (ListeningSocketsMixin supplies get_listening_sockets)
# ------------------------------------------------------------------ #
def _run_listening_sockets_command(self, command: str, *, privileged: bool) -> str:
"""The transport for ``ListeningSocketsMixin.get_listening_sockets``:
the exec path, which runs as root either way."""
return str(self._exec_ssh_command(command))
# ------------------------------------------------------------------ #
# Packages (Debian APT)
# ------------------------------------------------------------------ #
+1 -1
View File
@@ -25,7 +25,7 @@ classifiers = [
requires-python = ">=3.9"
dependencies = [
"napalm>=5.0.0",
"napalm_device_types>=2.3.0",
"napalm_device_types>=2.4.0",
"paramiko>=5.0.0", # CVE-2026-44405; imported directly for SSH fallback (driver.py)
"proxmoxer>=2.0.0",
"netaddr>=0.9.0",
+37
View File
@@ -0,0 +1,37 @@
"""`get_listening_sockets`: what listens on the node, and which service it is.
Whether pveproxy, a Ceph manager or a guest-facing service is reachable from
outside the node is decided by the address it listens on. The command and its
parse are napalm-device-types'; the driver only carries the command over its
exec path, which already runs as root.
"""
from __future__ import annotations
from unittest.mock import patch
from napalm_device_types import ListeningSocketsMixin
from napalm_proxmox.driver import ProxmoxDriver
WIRE = (
"SOCK_BEGIN\n[ss]\n"
'tcp LISTEN 0 4096 *:8006 *:* users:(("pveproxy worker",pid=2101,fd=6))\n'
"__SS_RC=0\n[cgroups]\n"
"2101 0::/system.slice/pveproxy.service\n"
"SOCK_END\n"
)
def test_the_driver_declares_the_contract():
assert issubclass(ProxmoxDriver, ListeningSocketsMixin)
def test_it_reads_as_root_over_the_exec_path(driver):
with patch.object(driver, "_exec_ssh_command", return_value=WIRE) as exec_:
reading = driver.get_listening_sockets()
[command] = [c.args[0] for c in exec_.call_args_list]
assert command.startswith("sh -c '")
assert reading["attributed"] is True
[socket] = reading["sockets"]
assert (socket["address"], socket["port"], socket["unit"]) == ("*", 8006, "pveproxy")