diff --git a/napalm_linux/linux.py b/napalm_linux/linux.py index 26a3b65..a15e95f 100644 --- a/napalm_linux/linux.py +++ b/napalm_linux/linux.py @@ -171,15 +171,16 @@ _NO_STDIN = "exec "$t" && printf %s "$t" || { s=$?; rm -f -- "$t"; exit $s; }; }' ) -#: What to do when sudo wants a password netOrk does not have. -_SUDO_PASSWORD_HINT = ( +#: What to do when sudo wants a password netOrk does not have (a message, not a password). +_SUDO_PASSWORD_HINT = ( # nosec B105 "sudo requires a password on this host and no sudo password was given: pass one, " "or allow this user passwordless sudo (NOPASSWD)." ) @@ -274,7 +275,10 @@ def _arm_vendor_from_model(model: str) -> str: #: Where net-snmp reads its configuration, and how each package manager installs it. _SNMPD_CONF = "/etc/snmp/snmpd.conf" _SNMP_INSTALL = { - "apt": "apt-get update -y >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y snmpd snmp 2>&1", + "apt": ( + "apt-get update -y >/dev/null 2>&1; " + "DEBIAN_FRONTEND=noninteractive apt-get install -y snmpd snmp 2>&1" + ), "dnf": "dnf install -y net-snmp net-snmp-utils 2>&1", "yum": "yum install -y net-snmp net-snmp-utils 2>&1", "apk": "apk add --no-cache net-snmp net-snmp-tools 2>&1", @@ -425,7 +429,7 @@ class LinuxDriver( "stty cols 10000 2>/dev/null || true", expect_string=r"[#$>]\s*$" ) except Exception: - pass + logger.debug("%s: ignored", self.hostname, exc_info=True) self._pkg_manager = self._forced_pkg_manager or self._detect_pkg_manager() logger.debug("Connected to %s, pkg_manager=%s", self.hostname, self._pkg_manager) @@ -436,7 +440,7 @@ class LinuxDriver( try: self._device.disconnect() except Exception: - pass + logger.debug("%s: ignored", self.hostname, exc_info=True) self._device = None self._pkg_manager = None @@ -668,8 +672,10 @@ class LinuxDriver( "u=$(cat /sys/class/dmi/id/product_uuid 2>/dev/null); " "d=$(systemd-detect-virt 2>/dev/null); d=${d:-none}; " "dt=$(tr -d '\\0' /dev/null); " - "cs=$(grep '^Serial' /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 | xargs 2>/dev/null); " - "cm=$(grep '^Model' /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 | xargs 2>/dev/null); " + "cs=$(grep '^Serial' /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 " + "| xargs 2>/dev/null); " + "cm=$(grep '^Model' /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 " + "| xargs 2>/dev/null); " # DMIBEGIN sentinel: _send() strips leading blank lines (ARM has no DMI # files, so fields 0-4 are empty). The sentinel anchors the output so # splitlines()[start+N] always maps to the correct field index. @@ -1075,7 +1081,7 @@ class LinuxDriver( _make_entry(mapped_proto, nexthop, iface, metric, prefix) ) except Exception: - pass + logger.debug("%s: ignored", self.hostname, exc_info=True) return routes @@ -1324,7 +1330,8 @@ class LinuxDriver( def _get_packages_rpm(self) -> list[PackageDict]: out = self._send( - "rpm -qa --queryformat '%{NAME}\\t%{VERSION}-%{RELEASE}\\t%{SIZE}\\t%{SUMMARY}\\n' 2>/dev/null" + "rpm -qa --queryformat " + "'%{NAME}\\t%{VERSION}-%{RELEASE}\\t%{SIZE}\\t%{SUMMARY}\\n' 2>/dev/null" ) packages: list[PackageDict] = [] for line in out.splitlines(): @@ -1863,19 +1870,7 @@ class LinuxDriver( passwd_out = self._send("getent passwd 2>/dev/null || cat /etc/passwd") groups_out = self._send("getent group 2>/dev/null || cat /etc/group") - # Build uid→[group] map from /etc/group - uid_to_groups: dict[int, list[str]] = {} - for line in groups_out.splitlines(): - parts = line.split(":") - if len(parts) < 4: - continue - gname = parts[0] - members = [m.strip() for m in parts[3].split(",") if m.strip()] - for member in members: - # We'll convert username→uid below; collect by username first - uid_to_groups.setdefault(-1, []) # placeholder - - # Simpler: collect username→groups, then join with passwd + # username → supplementary groups, joined with passwd below username_to_groups: dict[str, list[str]] = {} for line in groups_out.splitlines(): parts = line.split(":") @@ -1994,9 +1989,7 @@ class LinuxDriver( return jobs @staticmethod - def _parse_cron_line( - line: str, source_user: str, has_user_field: bool - ) -> CronJobDict | None: + def _parse_cron_line(line: str, source_user: str, has_user_field: bool) -> CronJobDict | None: """Parse a single crontab line; returns ``None`` for comments/blanks.""" stripped = line.strip() # Remove trailing comment @@ -2064,7 +2057,7 @@ class LinuxDriver( community = parts[3] break except Exception: - pass + logger.debug("%s: ignored", self.hostname, exc_info=True) # Detect port override try: @@ -2076,7 +2069,7 @@ class LinuxDriver( if m: port = int(m.group(1)) except Exception: - pass + logger.debug("%s: ignored", self.hostname, exc_info=True) return SNMPConfigDict(running=True, community=community, port=port, version="2c") except Exception as exc: diff --git a/tests/test_fix_templates.py b/tests/test_fix_templates.py index 18c3a4c..e1e3993 100644 --- a/tests/test_fix_templates.py +++ b/tests/test_fix_templates.py @@ -188,7 +188,7 @@ def test_every_annotation_resolves(): import inspect import typing - for name, member in inspect.getmembers(LinuxDriver, inspect.isfunction): + for _name, member in inspect.getmembers(LinuxDriver, inspect.isfunction): if member.__module__ == "napalm_linux.linux": typing.get_type_hints(member) diff --git a/tests/test_ssh_host_key.py b/tests/test_ssh_host_key.py index 35683a9..a1415f7 100644 --- a/tests/test_ssh_host_key.py +++ b/tests/test_ssh_host_key.py @@ -78,7 +78,7 @@ def test_a_changed_key_is_refused(): try: raise paramiko.BadHostKeyException("10.0.0.8", SERVER_KEY, OTHER_KEY) except paramiko.SSHException as exc: # what netmiko does with it - raise NetmikoTimeoutException(f"A paramiko SSHException occurred: {exc}") + raise NetmikoTimeoutException(f"A paramiko SSHException occurred: {exc}") from exc driver = _driver(seen, SshHostKey.of(OTHER_KEY)) with patch("napalm_linux.linux.ConnectHandler", side_effect=refuse):