fix: tell unattended-upgrade from Ubuntu's idle shutdown helper
CI / test (3.10) (push) Successful in 24s
CI / test (3.11) (push) Successful in 23s
CI / test (3.12) (push) Successful in 24s
CI / test (3.10) (pull_request) Successful in 24s
CI / test (3.11) (pull_request) Successful in 22s
CI / test (3.12) (pull_request) Successful in 25s
CI / test (3.10) (push) Successful in 24s
CI / test (3.11) (push) Successful in 23s
CI / test (3.12) (push) Successful in 24s
CI / test (3.10) (pull_request) Successful in 24s
CI / test (3.11) (pull_request) Successful in 22s
CI / test (3.12) (pull_request) Successful in 25s
On every Ubuntu host with unattended-upgrades, get_host_status() read the package manager as busy, so an interrupted dpkg was never reported there. Ubuntu keeps unattended-upgrade-shutdown --wait-for-signal running all the time; its process name is cut to 15 characters, unattended-upgr, the same as a real run's. BUSY_CHECK now matches dpkg, apt, apt-get and aptitude by name and unattended-upgrade by its command line. The tests run it through sh with a stand-in ps, and check that the command does not match itself: over an exec channel it is the command line of the shell that runs it. Closes #26
This commit is contained in:
@@ -11,10 +11,14 @@ The fixtures are the real states of six hosts on netOrk's test server.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from napalm_device_types import OSDriver
|
||||
from napalm_device_types.host_status import (
|
||||
BUSY_CHECK,
|
||||
HOST_STATUS_COMMAND,
|
||||
HostStatusMixin,
|
||||
kernel_reboot_pending,
|
||||
@@ -375,3 +379,52 @@ class TestAutoUpdatesLastSuccess:
|
||||
def test_the_command_reads_the_upgrade_stamp_only(self):
|
||||
assert "/var/lib/apt/periodic/upgrade-stamp" in HOST_STATUS_COMMAND
|
||||
assert "update-success-stamp" not in HOST_STATUS_COMMAND
|
||||
|
||||
|
||||
class TestBusyCheck:
|
||||
"""Whether a package manager is working right now, run through ``sh`` with a
|
||||
stand-in ``ps``. On Ubuntu, unattended-upgrades keeps
|
||||
``unattended-upgrade-shutdown --wait-for-signal`` running all the time; its
|
||||
process name is cut to 15 characters, ``unattended-upgr``, the same as a real
|
||||
run's. Taken for a run, it made every such host's dpkg state unknown -- aris
|
||||
among them (NetOrk/netork#738)."""
|
||||
|
||||
UBUNTU_IDLE = [
|
||||
("systemd", "/sbin/init"),
|
||||
("unattended-upgr", "/usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal"),
|
||||
("sshd", "sshd: netork [priv]"),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def _busy(tmp_path, processes) -> bool:
|
||||
comm = "\n".join(c for c, _ in processes)
|
||||
args = "\n".join(a for _, a in processes)
|
||||
ps = tmp_path / "ps"
|
||||
ps.write_text(
|
||||
"#!/bin/sh\n"
|
||||
f"case \"$*\" in *comm=*) printf '%s\\n' '{comm}';; *) printf '%s\\n' '{args}';; esac\n"
|
||||
)
|
||||
ps.chmod(0o755)
|
||||
env = {"PATH": f"{tmp_path}:/usr/bin:/bin"}
|
||||
out = subprocess.run(["sh", "-c", BUSY_CHECK], capture_output=True, text=True, env=env)
|
||||
return "[dpkg-busy]" in out.stdout
|
||||
|
||||
def test_the_shutdown_helper_of_an_idle_ubuntu_host_is_no_run(self, tmp_path):
|
||||
assert self._busy(tmp_path, self.UBUNTU_IDLE) is False
|
||||
|
||||
def test_unattended_upgrade_running(self, tmp_path):
|
||||
run = ("unattended-upgr", "/usr/bin/python3 /usr/bin/unattended-upgrade")
|
||||
|
||||
assert self._busy(tmp_path, [*self.UBUNTU_IDLE, run]) is True
|
||||
|
||||
@pytest.mark.parametrize("name", ["dpkg", "apt", "apt-get", "aptitude"])
|
||||
def test_dpkg_and_apt(self, tmp_path, name):
|
||||
assert self._busy(tmp_path, [*self.UBUNTU_IDLE, (name, f"/usr/bin/{name} upgrade")]) is True
|
||||
|
||||
def test_it_is_part_of_the_command(self):
|
||||
assert BUSY_CHECK in HOST_STATUS_COMMAND
|
||||
|
||||
def test_the_command_does_not_match_itself(self):
|
||||
"""Run over an exec channel, the command is the command line of the shell
|
||||
that runs it, and ``ps -o args`` lists it."""
|
||||
assert not re.search(r"(^|[ /])unattended-upgrade( |$)", HOST_STATUS_COMMAND)
|
||||
|
||||
Reference in New Issue
Block a user