feat: say where a pending update comes from, whether it is a security fix, and whether the host needs a reboot #6

Merged
christianmanivong merged 1 commits from feat/update-origin-host-status into main 2026-10-05 22:19:25 +00:00
Owner

For netOrk MVP 5 (patch management). It adds shared parsers and a host-status reader: where a pending update comes from, whether it is a security update, whether the host needs a reboot, and whether it patches itself. The commit message has the details.

It also adds the contract rule that a reader raises when it cannot read, and never returns [] for "don't know". netOrk keeps "pending since" per package, so a false empty list would reset those clocks.

Checked against real hosts (netOrk test server)

Host Updates read Host status
Ubuntu 24.04 (z2m-garden) 1, origin=noble, not security reboot required (/var/run/reboot-required), patches itself
Ubuntu 24.04 (vault-01) 1 no reboot, patches itself
Raspberry Pi OS 0 no reboot (two kernel flavours installed, the running one is the newest)
Debian 13 / OMV 2, stable-backports reboot required, patches itself
Proxmox VE 9 15, stable (Ceph) no reboot

Before the pipe, the OMV and Raspberry Pi reads broke on terminal codes. The fix is the | cat in both commands; strip_terminal_codes keeps any remaining codes out of the parsers.

Tests

$ PYTHONPATH=. pytest -q tests
312 passed
$ ruff check --isolated --line-length 100 <new and touched files>
All checks passed!
$ mypy napalm_device_types   # only the existing base.py / _ucd_metrics.py findings remain
For netOrk MVP 5 (patch management). It adds shared parsers and a host-status reader: where a pending update comes from, whether it is a security update, whether the host needs a reboot, and whether it patches itself. The commit message has the details. It also adds the contract rule that **a reader raises when it cannot read, and never returns `[]` for "don't know"**. netOrk keeps "pending since" per package, so a false empty list would reset those clocks. ## Checked against real hosts (netOrk test server) | Host | Updates read | Host status | |---|---|---| | Ubuntu 24.04 (z2m-garden) | 1, `origin=noble`, not security | reboot required (`/var/run/reboot-required`), patches itself | | Ubuntu 24.04 (vault-01) | 1 | no reboot, patches itself | | Raspberry Pi OS | 0 | no reboot (two kernel flavours installed, the running one is the newest) | | Debian 13 / OMV | 2, `stable-backports` | reboot required, patches itself | | Proxmox VE 9 | 15, `stable` (Ceph) | no reboot | Before the pipe, the OMV and Raspberry Pi reads broke on terminal codes. The fix is the `| cat` in both commands; `strip_terminal_codes` keeps any remaining codes out of the parsers. ## Tests ``` $ PYTHONPATH=. pytest -q tests 312 passed $ ruff check --isolated --line-length 100 <new and touched files> All checks passed! $ mypy napalm_device_types # only the existing base.py / _ucd_metrics.py findings remain ```
christianmanivong added 1 commit 2026-10-05 22:19:24 +00:00
netOrk MVP 5 measures "security updates applied within N days" and starts
patch runs inside agreed windows. That needs three things every Linux driver
reads the same way, so they live here once:

- UpdateDict gains optional `origin` and `security` (None = unknown).
- package_updates: APT_UPGRADABLE_COMMAND and parse_apt_upgradable(). apt's
  suites are the origin; a "-security" suite makes it a security update;
  several architectures of one package are one entry. The command runs
  through a pipe with its exit status printed inside the group: through a
  pseudo-terminal apt drew progress and keypad codes, one of which (ESC >)
  a screen-scraping read took for a prompt and stopped at. The parser raises
  ValueError when apt failed or its status never arrived.
  DNF_SECURITY_COMMAND / parse_dnf_security() / nevra_name() for dnf/yum.
- host_status: HOST_STATUS_COMMAND, parse_host_status(), HostStatusMixin
  (template form, hook _run_host_status_command). reboot_required from
  /var/run/reboot-required, needs-restarting -r, or a newer kernel of the
  running flavour (a Raspberry Pi carries two flavours side by side);
  auto_updates from APT::Periodic::Unattended-Upgrade with its timer, or
  dnf-automatic. HostStatusDict in models.py.
- terminal.strip_terminal_codes(): CSI, OSC and two-character escapes, now
  also used by the systemd parser.
- UpdateMixin: contract refresh_available_updates(); get_available_updates'
  docstring now states the rule that a reader raises when it cannot read and
  never returns [] for "don't know".

Fixtures are real output from Ubuntu 24.04, Debian 13 / OMV, Raspberry Pi OS
and Proxmox VE 9. Version 2.3.0.
christianmanivong merged commit c2d8d4a0d2 into main 2026-10-05 22:19:25 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: NAPALM/napalm-device-types#6