feat: read the service clusters a host belongs to (0.10.0)
CI / test (3.10) (pull_request) Successful in 25s
CI / test (3.11) (pull_request) Successful in 24s
CI / test (3.12) (pull_request) Successful in 26s
CI / test (3.10) (push) Successful in 25s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 25s
CI / test (3.10) (pull_request) Successful in 25s
CI / test (3.11) (pull_request) Successful in 24s
CI / test (3.12) (pull_request) Successful in 26s
CI / test (3.10) (push) Successful in 25s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 25s
LinuxDriver mixes in napalm-device-types' ServiceClustersMixin (4.17.0): get_service_clusters() reads Patroni's members and roles, adguardhome-sync's origin and replicas and a BunkerWeb worker's manager from the host's own configuration -- the evidence that two hosts run one service, not merely answer at one address (NetOrk/netork#1125). _run_service_clusters_command carries the shared command on an exec channel, root first, like the virtual IPs' one.
This commit is contained in:
1 parent
c8e2b328d7
commit
427a9ac8af
3 files changed
+49
-2
No files matched your search
@@ -46,6 +46,7 @@ from napalm_device_types import (
|
|||||||
OpenSshServerMixin,
|
OpenSshServerMixin,
|
||||||
OSDriver,
|
OSDriver,
|
||||||
PackageProxyMixin,
|
PackageProxyMixin,
|
||||||
|
ServiceClustersMixin,
|
||||||
SnmpAgentMixin,
|
SnmpAgentMixin,
|
||||||
SystemIdentityMixin,
|
SystemIdentityMixin,
|
||||||
SystemdServicesMixin,
|
SystemdServicesMixin,
|
||||||
@@ -294,6 +295,7 @@ class LinuxDriver(
|
|||||||
KernelFactsMixin,
|
KernelFactsMixin,
|
||||||
ListeningSocketsMixin,
|
ListeningSocketsMixin,
|
||||||
VirtualIpsMixin,
|
VirtualIpsMixin,
|
||||||
|
ServiceClustersMixin,
|
||||||
SystemIdentityMixin,
|
SystemIdentityMixin,
|
||||||
OpenSshServerMixin,
|
OpenSshServerMixin,
|
||||||
SystemdServicesMixin,
|
SystemdServicesMixin,
|
||||||
@@ -1179,6 +1181,13 @@ class LinuxDriver(
|
|||||||
"""
|
"""
|
||||||
return self.run_command(command, privileged=privileged, timeout=60).stdout
|
return self.run_command(command, privileged=privileged, timeout=60).stdout
|
||||||
|
|
||||||
|
def _run_service_clusters_command(self, command: str, *, privileged: bool) -> str:
|
||||||
|
"""The transport for ``ServiceClustersMixin.get_service_clusters``: an exec
|
||||||
|
channel, like the virtual IPs' command, which it resembles in size.
|
||||||
|
Read-only either way; root only because Patroni's configuration is the
|
||||||
|
postgres user's alone."""
|
||||||
|
return self.run_command(command, privileged=privileged, timeout=60).stdout
|
||||||
|
|
||||||
def _run_system_identity_command(self, command: str, *, privileged: bool) -> str:
|
def _run_system_identity_command(self, command: str, *, privileged: bool) -> str:
|
||||||
"""The transport for ``SystemIdentityMixin.get_system_identity``: an exec channel,
|
"""The transport for ``SystemIdentityMixin.get_system_identity``: an exec channel,
|
||||||
as root, since ``product_uuid`` and ``product_serial`` are root's."""
|
as root, since ``product_uuid`` and ``product_serial`` are root's."""
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "napalm-linux"
|
name = "napalm-linux"
|
||||||
version = "0.9.0"
|
version = "0.10.0"
|
||||||
description = "NAPALM driver for generic Linux systems via SSH"
|
description = "NAPALM driver for generic Linux systems via SSH"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
@@ -37,7 +37,7 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"napalm>=4.0",
|
"napalm>=4.0",
|
||||||
"napalm-device-types>=4.14.0",
|
"napalm-device-types>=4.17.0",
|
||||||
"netmiko>=4.0.0",
|
"netmiko>=4.0.0",
|
||||||
"paramiko>=5.0.0", # CVE-2026-44405
|
"paramiko>=5.0.0", # CVE-2026-44405
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1721,6 +1721,44 @@ class TestGetVirtualIps:
|
|||||||
assert plain.startswith("sh -c '")
|
assert plain.startswith("sh -c '")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# get_service_clusters (napalm-device-types ServiceClustersMixin)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_CLUSTERS = (
|
||||||
|
"SVCC_BEGIN\n[systemd]\n[patroni patroni.service]\nactive active\nscope netork-db\n"
|
||||||
|
"name db-01\nrestapi 10.7.234.12:8008\nrest-unreachable\n[no-docker]\nSVCC_END\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetServiceClusters:
|
||||||
|
"""The same template as get_virtual_ips: an exec channel, root first."""
|
||||||
|
|
||||||
|
_exec = staticmethod(TestGetVirtualIps._exec)
|
||||||
|
|
||||||
|
def test_it_reads_with_the_shared_command_on_an_exec_channel(self, driver):
|
||||||
|
from napalm_device_types import ServiceClustersMixin
|
||||||
|
|
||||||
|
assert isinstance(driver, ServiceClustersMixin)
|
||||||
|
calls = self._exec(driver, (_CLUSTERS, "", 0))
|
||||||
|
|
||||||
|
reading = driver.get_service_clusters()
|
||||||
|
|
||||||
|
assert reading["patroni"][0]["cluster"] == "netork-db"
|
||||||
|
[(command, privileged)] = calls
|
||||||
|
assert privileged is True
|
||||||
|
assert command.startswith("sh -c '")
|
||||||
|
driver._device.send_command.assert_not_called()
|
||||||
|
|
||||||
|
def test_when_sudo_refuses_it_reads_what_the_user_may_see(self, driver):
|
||||||
|
calls = self._exec(driver, ("", "sudo: a password is required\n", 1), (_CLUSTERS, "", 0))
|
||||||
|
|
||||||
|
reading = driver.get_service_clusters()
|
||||||
|
|
||||||
|
assert reading["bunkerweb"] == []
|
||||||
|
assert [privileged for _, privileged in calls] == [True, False]
|
||||||
|
|
||||||
|
|
||||||
class TestHardensItsSshServer:
|
class TestHardensItsSshServer:
|
||||||
"""A stock Linux host runs a stock OpenSSH: the hardening netOrk offers for
|
"""A stock Linux host runs a stock OpenSSH: the hardening netOrk offers for
|
||||||
ssh-audit findings comes from napalm-device-types, carried over run_command
|
ssh-audit findings comes from napalm-device-types, carried over run_command
|
||||||
|
|||||||
Reference in new issue
Block a user