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