diff --git a/napalm_linux/linux.py b/napalm_linux/linux.py index b50dc05..14f5323 100644 --- a/napalm_linux/linux.py +++ b/napalm_linux/linux.py @@ -80,6 +80,9 @@ class LinuxDriver(OSDriver): self._secret: str = optional_args.get("secret", password) # Optional sudo password for privilege escalation (e.g. apt-get update) self._sudo_password: Optional[str] = optional_args.get("sudo_password") + # Expected apt proxy URL — checked as a device warning on apt systems. + # Only set when apt_proxy_enabled=true in NetOrk settings; empty string disables the check. + self._apt_proxy_url: str = optional_args.get("apt_proxy_url", "") if optional_args.get("debugging"): logger.setLevel(logging.DEBUG) @@ -788,6 +791,7 @@ class LinuxDriver(OSDriver): Currently detects: - package updates available (uses local package cache) + - apt proxy not configured (apt systems only) """ warnings: List[Dict[str, Any]] = [] try: @@ -805,6 +809,18 @@ class LinuxDriver(OSDriver): "packages": [u.get("name", "") for u in updates], }, }) + if self._pkg_manager == "apt" and self._apt_proxy_url: + try: + current = self._send("cat /etc/apt/apt.conf.d/00proxy 2>/dev/null || true").strip() + if self._apt_proxy_url not in current: + warnings.append({ + "code": "apt_proxy_missing", + "severity": "warning", + "action": "fix_apt_proxy", + "meta": {"expected_url": self._apt_proxy_url}, + }) + except Exception as exc: + logger.warning("get_device_warnings: apt proxy check failed: %s", exc) return warnings def _get_updates_apt(self) -> List[UpdateDict]: @@ -1616,6 +1632,8 @@ class LinuxDriver(OSDriver): return self._action_fix_docker_permissions() if action == "fix_snmp": return self._action_fix_snmp() + if action == "fix_apt_proxy": + return self._action_fix_apt_proxy() raise NotImplementedError(f"Unknown action: {action!r}") def _action_fix_snmp(self) -> DeviceActionResultDict: @@ -1750,6 +1768,29 @@ class LinuxDriver(OSDriver): out = f"Added {user!r} to the docker group. Reconnect or run a new poll to verify." return {"success": success, "output": out} + def _action_fix_apt_proxy(self) -> DeviceActionResultDict: + """Write /etc/apt/apt.conf.d/00proxy with the configured proxy URL.""" + import base64 as _b64 + proxy_url = self._apt_proxy_url + if not proxy_url: + return {"success": False, "output": "No apt_proxy_url configured."} + if self._pkg_manager != "apt": + return {"success": False, "output": f"Package manager is {self._pkg_manager!r}, not apt — skipping."} + + content = f'Acquire::http::Proxy "{proxy_url}";\n' + content_b64 = _b64.b64encode(content.encode()).decode() + self._send(f"echo {content_b64} | base64 -d > /tmp/netork_00proxy") + self._sudo( + "mv /tmp/netork_00proxy /etc/apt/apt.conf.d/00proxy && " + "chown root:root /etc/apt/apt.conf.d/00proxy && " + "chmod 644 /etc/apt/apt.conf.d/00proxy" + ) + verify = self._send("cat /etc/apt/apt.conf.d/00proxy 2>/dev/null").strip() + success = proxy_url in verify + if success: + return {"success": True, "output": f"Wrote /etc/apt/apt.conf.d/00proxy — proxy: {proxy_url}"} + return {"success": False, "output": f"Write may have failed. File content: {verify[:200]}"} + def get_vpn_tunnels(self) -> Dict[str, Any]: """Return WireGuard status via ``wg show all dump`` (requires root/sudo).