Files
napalm-bsd/README.md
T
Christian Manivong 25308bf747
CI / test (3.10) (push) Successful in 26s
CI / test (3.11) (push) Successful in 25s
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 26s
fix: raise when an update reader cannot read, and report host status
netOrk reads an empty update list as "no updates" and closes every patch
clock on the host. A refused sudo, a failing pkg, syspatch or freebsd-update,
or a pkg database pkg cannot read used to come back as that empty list. Each
of these now raises. Only pkg's "is not installed" still means no packages.

BsdDriver takes on napalm-device-types' HostStatusMixin. On FreeBSD it
reports a host whose installed kernel differs from the running one as
needing a reboot (device-types 4.1). OpenBSD stays unknown.

Closes #4
2026-10-08 12:08:44 +02:00

5.2 KiB

napalm-bsd

NAPALM drivers for FreeBSD (freebsd) and OpenBSD (openbsd) hosts, over SSH, built on napalm-device-types' OSDriver. Written for netOrk, which provisions and manages BSD VMs (NetOrk/netork#792).

Design

  • One shared BsdDriver (napalm_bsd/base.py) holds the SSH layer and every reader whose tools agree between the BSDs. FreeBSDDriver and OpenBSDDriver name only the commands that differ (hostname, release, kernel, hardware, netstat -rnW vs -rn).
  • Every command runs on its own SSH exec channel (run_on_transport from napalm-device-types): no PTY to parse a prompt from, stdout and stderr apart, a real exit status. run_command() / open_stream() are public (CommandChannelMixin).
  • Root comes from sudo -S with the sudo password on stdin (never on a command line), or sudo -n without one, as in napalm-linux. netOrk provisions sudo on BSD VMs for that reason; doas cannot read a password from stdin.
  • Parsing is in napalm_bsd/parse.py, pure functions tested on output recorded from real systems (tests/fixtures/, each directory's COMMANDS.txt lists what produced it).

Supported getters

Getter FreeBSD OpenBSD Source
get_facts ✓ ✓ kern.hostname/hostname, freebsd-version/uname, kenv smbios.*/hw.*, kern.boottime
get_interfaces, get_interfaces_ip ✓ ✓ ifconfig -a
get_route_to ✓ ✓ netstat -rnW / netstat -rn
get_arp_table ✓ ✓ arp -an
get_lldp_neighbors {} {} no LLDP daemon in either base system
get_users, get_processes, get_cron_jobs ✓ ✓ /etc/passwd+/etc/group, ps … lstart, system crontab + crontab -l
get_listening_sockets ✓ ✓ sockstat -46lq / fstat -n as root, netstat -an without
get_packages, install_package, uninstall_package ✓ ✓ pkg query / pkg install, pkg delete; pkg_info / pkg_add -I, pkg_delete
get_available_updates ✓ ✓ pkg upgrade -n + pkg audit (VuXML); pkg_add -u -n -v + syspatch -c
get_services, manage_service ✓ ✓ service -e + service … status / service … <action>; rcctl ls on + rcctl check / rcctl <action>
run_device_action("fix_snmp"), get_snmp_config ✓ ✓ net-snmp from packages: /usr/local/etc/snmp/snmpd.conf + service snmpd; /etc/snmp/snmpd.conf + rcctl … netsnmpd
get_host_status ✓ unknown napalm-device-types' host status: on FreeBSD freebsd-version -k vs -r (4.1+)

get_listening_sockets has the shape of napalm-device-types' ListeningSocketsMixin (whose ss/cgroup reading is Linux's) and its rule: read as root first, without root when that brings nothing back (attributed: False). FreeBSD's sockstat sees every socket either way; OpenBSD's fstat shows a user only their own processes, so without root the sockets come from netstat -an, unnamed.

There is deliberately no get_kernel_facts: KernelFactsMixin reports a Linux kernel's modules and CONFIG_* options, which a BSD kernel does not have, and hasattr(driver, "get_kernel_facts") has to stay truthful.

Updates. security on FreeBSD comes from VuXML (pkg audit): True for a package it lists as vulnerable, False for one it does not, None when the audit could not run. OpenBSD's tools do not say, so it is None there. Base-system patches are one entry, base-system (NetOrk/netork#799): OpenBSD's syspatch applies its patches together and in order; a classic FreeBSD base reports what freebsd-update has fetched (updatesready). On FreeBSD with pkgbase the base system is packages from the FreeBSD-base repository and needs no extra entry.

A reader that cannot read raises rather than return an empty list: netOrk takes [] as "no updates" and would close every patch clock on the host. That covers a refused sudo, a failing pkg, syspatch or freebsd-update, and a pkg database pkg cannot read (only pkg's "not installed" means no packages).

Reboot. get_host_status reports a FreeBSD host whose installed kernel (freebsd-version -k) differs from the running one (-r) as needing a reboot. OpenBSD has no such reading yet, so it stays unknown there.

Services are the enabled ones. FreeBSD reads their status as root, as root-only pidfiles hide a daemon from anyone else, and without root when sudo refuses; OpenBSD's rcctl check needs no root. Actions run as root.

SNMP is net-snmp from packages (NetOrk/netork#800), configured as netOrk does on Linux (v2c, community public, every address), so the agent answers UCD-SNMP-MIB for netOrk's health metrics. Memory, swap and load are right on both systems. CPU: FreeBSD reports ssCpuIdle about a minute after the agent starts; on OpenBSD net-snmp's CPU figures are wrong (0 % idle on an idle machine, also in hrProcessorLoad).

Connection arguments

optional_args: port (22), key_file, sudo_password, allow_agent, look_for_keys (both off by default).

Development

pip install "napalm-device-types @ git+https://git.netork.io/NAPALM/napalm-device-types.git"
pip install -e ".[dev]"
pytest