feat: packages, services and updates
CI / test (3.10) (push) Successful in 26s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 26s
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 25s
CI / test (3.10) (push) Successful in 26s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 26s
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 25s
The write side NetOrk/netork#799 needs, on both drivers. - Packages: get_packages (FreeBSD `pkg query` with the repository as source, nothing on a classic system without pkg; OpenBSD `pkg_info`), install_package / uninstall_package as root (`pkg install`/`pkg delete`, `pkg_add -I`/`pkg_delete`), names checked before anything is sent, a failure raised with what the tool printed. - Updates: get_available_updates. FreeBSD `pkg upgrade -n`, with `security` from VuXML (`pkg audit`: True for a listed package, False for any other, None when the audit could not run); OpenBSD `pkg_add -u -n -v` (no security verdict). Base-system patches are one `base-system` entry, as decided in #799: OpenBSD's `syspatch -c`, and on a classic FreeBSD what `freebsd-update` has fetched; on pkgbase the base system is packages from FreeBSD-base. - Services: get_services lists the enabled ones (FreeBSD `service ... status` as root, as root-only pidfiles hide daemons otherwise, without root when sudo refuses; OpenBSD `rcctl check`), manage_service runs start/stop/restart/enable/disable as root and returns success and output. Fixtures recorded on the FreeBSD 15.1 and OpenBSD 7.9 VMs with genuinely outdated packages (FreeBSD pointed at the latest branch, an OpenBSD package taken back to its release build). Checked live on both, including a service restart and installing and removing a package.
This commit is contained in:
+51
-1
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
from napalm_device_types import FingerprintRule
|
||||
|
||||
from napalm_bsd import parse
|
||||
from napalm_bsd.base import BsdDriver
|
||||
from napalm_bsd.base import BASE_SYSTEM, BsdDriver
|
||||
|
||||
|
||||
class OpenBSDDriver(BsdDriver):
|
||||
@@ -33,6 +33,56 @@ class OpenBSDDriver(BsdDriver):
|
||||
def _parse_listening(self, output: str, *, attributed: bool) -> list[dict]:
|
||||
return parse.fstat_sockets(output) if attributed else parse.netstat_listening(output)
|
||||
|
||||
INSTALL_COMMAND = "pkg_add -I {name}"
|
||||
UNINSTALL_COMMAND = "pkg_delete {name}"
|
||||
# rcctl check needs no root; "rcctl ls started" does.
|
||||
SERVICE_STATUS_COMMAND = (
|
||||
"for s in $(rcctl ls on); do "
|
||||
"if rcctl check $s >/dev/null 2>&1; then r=1; else r=0; fi; "
|
||||
'printf "%s\\t%s\\n" "$s" "$r"; done'
|
||||
)
|
||||
SERVICE_ACTION_COMMAND = "rcctl {action} {name}"
|
||||
|
||||
def _parse_services(self, output: str) -> list[dict]:
|
||||
return parse.rcctl_check(output)
|
||||
|
||||
def get_services(self) -> list[dict]:
|
||||
return self._parse_services(self._out(self.SERVICE_STATUS_COMMAND, timeout=120))
|
||||
|
||||
def get_packages(self) -> list[dict]:
|
||||
return parse.pkg_info(self._out("pkg_info"))
|
||||
|
||||
def get_available_updates(self) -> list[dict]:
|
||||
"""Package updates from ``pkg_add -u -n -v``, and the base system's syspatches.
|
||||
|
||||
syspatch applies its patches together and in order, so they are one
|
||||
entry (#799). Neither tool says which update is a security fix.
|
||||
"""
|
||||
updates: list[dict] = [
|
||||
{**candidate, "origin": None, "security": None}
|
||||
for candidate in parse.pkg_add_candidates(
|
||||
self._out("pkg_add -u -n -v", privileged=True, timeout=300)
|
||||
)
|
||||
]
|
||||
patches = parse.syspatch(self._out("syspatch -c", privileged=True, timeout=120))
|
||||
if patches:
|
||||
installed = parse.syspatch(self._out("syspatch -l", privileged=True))
|
||||
summary = (
|
||||
", ".join(patches)
|
||||
if len(patches) <= 3
|
||||
else f"{len(patches)} patches: {patches[0]} … {patches[-1]}"
|
||||
)
|
||||
updates.append(
|
||||
{
|
||||
"name": BASE_SYSTEM,
|
||||
"current_version": installed[-1] if installed else self._out("uname -r"),
|
||||
"new_version": summary,
|
||||
"origin": "syspatch",
|
||||
"security": None,
|
||||
}
|
||||
)
|
||||
return updates
|
||||
|
||||
def _hardware(self) -> tuple[str, str, str]:
|
||||
hw = self._platform()
|
||||
return hw.get("vendor", ""), hw.get("product", ""), hw.get("serialno", "")
|
||||
|
||||
Reference in New Issue
Block a user