fix: adapt to napalm-device-types 4.7
CI / test (3.10) (push) Successful in 38s
CI / test (3.11) (push) Successful in 37s
CI / test (3.12) (push) Successful in 39s

napalm-device-types 4.7 changed three things this driver depends on:

- parse_dnf_security needs the "__DNF_RC=<status>" line that
  DNF_SECURITY_COMMAND prints and raises ValueError without it or when dnf
  failed. The yum security query had no such line, so listing updates on
  any yum host raised. _YUM_SECURITY_COMMAND now prints the marker the same
  way ("{ ...; echo __DNF_RC=$?; } | cat"). _rpm_security_names checks
  __DNF_RC itself and turns a failed query, or output cut short before the
  marker, into None (security unknown) rather than "no advisories" or an
  exception.
- OSDriver.get_users was renamed to get_os_users, since NAPALM's own
  get_users has another shape. LinuxDriver.get_users is now get_os_users
  with the same return value.
- run_on_transport reads an exec channel to EOF after its exit status
  arrives; the tests' fake channels gain recv/recv_stderr for that.

Require napalm-device-types>=4.7.1 and bump the version to 0.6.0.
This commit is contained in:
christianmanivong committed 2026-10-13 06:25:17 +00:00
1 parent 81b2df9d71
commit 350e3a6d6e
8 files changed
+141 -15

No files matched your search

+88 -8
View File
@@ -4,7 +4,12 @@ import re
import pytest
from unittest.mock import MagicMock, patch
from napalm_linux.linux import LinuxDriver, _arm_vendor_from_model, _split_status
from napalm_linux.linux import (
_YUM_SECURITY_COMMAND,
LinuxDriver,
_arm_vendor_from_model,
_split_status,
)
# ---------------------------------------------------------------------------
@@ -93,6 +98,9 @@ class _AnsweringChannel:
def recv_stderr_ready(self):
return False
def recv_stderr(self, size):
return b""
def exit_status_ready(self):
return not self._out
@@ -309,7 +317,7 @@ def test_get_available_updates_apt(driver):
# ---------------------------------------------------------------------------
# get_users
# get_os_users
# ---------------------------------------------------------------------------
@@ -326,9 +334,9 @@ GROUP_OUT = (
)
def test_get_users(driver):
def test_get_os_users(driver):
with patch.object(driver, "_send", side_effect=[PASSWD_OUT, GROUP_OUT]):
users = driver.get_users()
users = driver.get_os_users()
admin = next(u for u in users if u["username"] == "admin")
assert admin["uid"] == 1000
@@ -338,6 +346,14 @@ def test_get_users(driver):
assert set(admin["groups"]) == {"sudo", "docker", "adm"}
def test_get_users_is_left_to_napalm(driver):
"""napalm-device-types 4.7 renamed OSDriver.get_users to get_os_users:
NAPALM's own get_users has another shape, and this driver does not implement it."""
assert LinuxDriver.get_users is not LinuxDriver.get_os_users
with pytest.raises(NotImplementedError):
driver.get_users()
# ---------------------------------------------------------------------------
# ping parsing
# ---------------------------------------------------------------------------
@@ -1460,9 +1476,12 @@ class TestAvailableUpdates:
driver._pkg_manager = "dnf"
driver._device.send_command.side_effect = [
"0", # id -u
"openssl-libs.x86_64 1:3.1.4-2.fc40 updates\n"
"vim-enhanced.x86_64 2:9.1.083-1.fc40 updates\n__NETORK_RC=100",
"FEDORA-2024-1a2b3c4d5e Important/Sec. openssl-libs-1:3.1.4-2.fc40.x86_64\n__NETORK_RC=0",
("openssl-libs.x86_64 1:3.1.4-2.fc40 updates\n"
"vim-enhanced.x86_64 2:9.1.083-1.fc40 updates\n__NETORK_RC=100"),
# DNF_SECURITY_COMMAND pipes through cat: the outer status is cat's, dnf's own
# is in the __DNF_RC marker.
("FEDORA-2024-1a2b3c4d5e Important/Sec. openssl-libs-1:3.1.4-2.fc40.x86_64\n"
"__DNF_RC=0\n__NETORK_RC=0"),
]
updates = {u["name"]: u for u in driver.get_available_updates()}
@@ -1475,7 +1494,62 @@ class TestAvailableUpdates:
driver._device.send_command.side_effect = [
"0",
"vim-enhanced.x86_64 2:9.1.083-1.fc40 updates\n__NETORK_RC=100",
"Error: updateinfo metadata missing\n__NETORK_RC=1",
"Error: updateinfo metadata missing\n__DNF_RC=1\n__NETORK_RC=0",
]
assert driver.get_available_updates()[0]["security"] is None
def test_yum_security_command_reports_its_own_exit_status(self):
# parse_dnf_security (napalm-device-types 4.7) needs the __DNF_RC marker, and
# behind "| cat" the outer status no longer says whether yum failed.
assert "echo __DNF_RC=$?" in _YUM_SECURITY_COMMAND
assert "yum updateinfo list security" in _YUM_SECURITY_COMMAND
def test_yum_marks_what_a_security_advisory_covers(self, driver):
driver._pkg_manager = "yum"
driver._device.send_command.side_effect = [
"0", # id -u
("openssl-libs.x86_64 1:1.0.2k-26.el7_9 updates\n"
"vim-enhanced.x86_64 2:7.4.629-8.el7_9 updates\n__NETORK_RC=100"),
("RHSA-2023:3556 Important/Sec. openssl-libs-1:1.0.2k-26.el7_9.x86_64\n"
"__DNF_RC=0\n__NETORK_RC=0"),
]
updates = {u["name"]: u for u in driver.get_available_updates()}
assert driver._device.send_command.call_count == 3
assert "echo __DNF_RC=$?" in driver._device.send_command.call_args_list[2][0][0]
assert updates["openssl-libs"]["security"] is True
assert updates["vim-enhanced"]["security"] is False
def test_yum_with_no_advisories_marks_nothing_as_security(self, driver):
driver._pkg_manager = "yum"
driver._device.send_command.side_effect = [
"0",
"vim-enhanced.x86_64 2:7.4.629-8.el7_9 updates\n__NETORK_RC=100",
"__DNF_RC=0\n__NETORK_RC=0",
]
assert driver.get_available_updates()[0]["security"] is False
def test_yum_that_failed_leaves_security_unknown(self, driver):
# A failed yum prints nothing on stdout (2>/dev/null): read as "no advisories",
# every update would be marked as not a security fix.
driver._pkg_manager = "yum"
driver._device.send_command.side_effect = [
"0",
"vim-enhanced.x86_64 2:7.4.629-8.el7_9 updates\n__NETORK_RC=100",
"__DNF_RC=1\n__NETORK_RC=0",
]
assert driver.get_available_updates()[0]["security"] is None
def test_yum_without_its_exit_status_leaves_security_unknown(self, driver):
driver._pkg_manager = "yum"
driver._device.send_command.side_effect = [
"0",
"vim-enhanced.x86_64 2:7.4.629-8.el7_9 updates\n__NETORK_RC=100",
"RHSA-2023:3556 Important/Sec. vim-enhanced-2:7.4.629-8.el7_9.x86_64\n__NETORK_RC=0",
]
assert driver.get_available_updates()[0]["security"] is None
@@ -1725,9 +1799,15 @@ class TestGetVirtualIps:
def recv_ready(self):
return False
def recv(self, size):
return b""
def recv_stderr_ready(self):
return False
def recv_stderr(self, size):
return b""
def exit_status_ready(self):
return True