From a7ecc6427c4c342f1673a30950cfcbdd272a4f45 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Mon, 29 Jun 2026 15:13:40 +0200 Subject: [PATCH] =?UTF-8?q?fix(get=5Fconfig):=20use=20openssh+sshpass=20su?= =?UTF-8?q?bprocess=20=E2=80=94=20bypasses=20paramiko=20Mocana=20compat=20?= =?UTF-8?q?issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit paramiko 4.x is incompatible with Mocana SSH 6.3 on HP 2530/YA firmware. OpenSSH subprocess with +diffie-hellman-group1-sha1 kex works correctly and connects in < 5s instead of hitting the 15s banner timeout. --- napalm_procurve/procurve.py | 64 ++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/napalm_procurve/procurve.py b/napalm_procurve/procurve.py index e264248..698fca2 100644 --- a/napalm_procurve/procurve.py +++ b/napalm_procurve/procurve.py @@ -592,40 +592,52 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver): return {"running": running, "startup": startup, "candidate": candidate} def _get_config_via_ssh(self) -> str: - """Open a one-shot SSH session to retrieve running-config. + """Retrieve running-config via OpenSSH subprocess (sshpass + ssh). - Used as fallback when the REST API does not expose the config endpoint - (e.g. HP 2530 / YA firmware with Mocana SSH). - - Uses SSHClient.connect() with the same approach as the netOrk SSH - console link (_paramiko_connect in _helpers.py) — no algorithm - overrides, plain password auth, 15-second banner timeout. + paramiko is incompatible with Mocana SSH 6.3 on HP 2530 / YA firmware. + OpenSSH has better legacy algorithm support and connects where paramiko + fails. Requires openssh-client + sshpass installed in the environment. """ - import paramiko + import shutil + import subprocess - _TIMEOUT = 15 + _TIMEOUT = 12 + if not shutil.which("sshpass") or not shutil.which("ssh"): + logger.warning("sshpass/ssh not available — skipping SSH config fallback for %s", self.hostname) + return "" + + cmd = [ + "sshpass", "-p", self.password or "", + "ssh", + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + "-o", f"ConnectTimeout={_TIMEOUT}", + "-o", "BatchMode=no", + "-o", "KexAlgorithms=+diffie-hellman-group1-sha1,diffie-hellman-group14-sha1", + "-o", "HostKeyAlgorithms=+ssh-rsa", + "-p", str(self.port or 22), + f"{self.username}@{self.hostname}", + "show running-config", + ] try: - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - client.connect( - hostname=self.hostname, - port=self.port or 22, - username=self.username, - password=self.password, - timeout=_TIMEOUT, - banner_timeout=_TIMEOUT, - auth_timeout=_TIMEOUT, - look_for_keys=False, - allow_agent=False, + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=_TIMEOUT + 3, ) - _, stdout, _ = client.exec_command("show running-config", timeout=_TIMEOUT) - config = stdout.read().decode("utf-8", errors="replace") - client.close() - return config + if result.returncode == 0 and result.stdout.strip(): + return result.stdout + logger.warning( + "SSH config fallback (openssh) failed for %s: rc=%s err=%s", + self.hostname, result.returncode, result.stderr[:200], + ) + except subprocess.TimeoutExpired: + logger.warning("SSH config fallback timed out for %s", self.hostname) except Exception as exc: logger.warning("SSH config fallback failed for %s: %s", self.hostname, exc) - return "" + return "" # ------------------------------------------------------------------ # NAPALM: get_environment