fix(get_config): use paramiko directly with group1-sha1 for Mocana SSH 6.3

- Replace netmiko with direct paramiko connection for SSH config fallback
- Explicitly set preferred_kex to include diffie-hellman-group1-sha1
  (required by old Mocana SSH 6.3 on HP 2530 / YA firmware)
- Hard timeout caps: banner_timeout=auth_timeout=8s, no keys/agent
This commit is contained in:
Christian Manivong
2026-06-29 13:53:09 +02:00
parent 8a182c4fa4
commit 831727f2af
+49 -21
View File
@@ -590,30 +590,58 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
"""Open a one-shot SSH session to retrieve running-config. """Open a one-shot SSH session to retrieve running-config.
Used as fallback when the REST API does not expose the config endpoint Used as fallback when the REST API does not expose the config endpoint
(e.g. HP 2530 / YA firmware). Tries legacy KEX first (required for (e.g. HP 2530 / YA firmware with Mocana SSH).
older ProCurve firmware), then standard. Each attempt is capped at
8 seconds so this fallback never pushes the overall poll over budget. Uses paramiko directly (not netmiko) to:
Returns empty string on any failure. - Explicitly enable diffie-hellman-group1-sha1 (required by Mocana SSH 6.3)
- Keep total blocking time ≤ 10 seconds
""" """
_FALLBACK_TIMEOUT = 8 # seconds per attempt — keeps total ≤ 16 s import paramiko
for legacy in (True, False):
_FALLBACK_TIMEOUT = 8
# KEX list that includes the old group1-sha1 required by Mocana SSH 6.3
_LEGACY_KEX = [
"diffie-hellman-group1-sha1",
"diffie-hellman-group14-sha1",
"diffie-hellman-group14-sha256",
"diffie-hellman-group-exchange-sha256",
]
_LEGACY_DISABLED = {
"pubkeys": ["rsa-sha2-256", "rsa-sha2-512"],
}
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Patch the preferred kex list on the class before connecting so
# paramiko will negotiate group1-sha1 with the old Mocana SSH server.
orig_kex = paramiko.Transport._preferred_kex
try: try:
kwargs = self._netmiko_kwargs(legacy=legacy) paramiko.Transport._preferred_kex = tuple(_LEGACY_KEX)
kwargs["timeout"] = _FALLBACK_TIMEOUT client.connect(
conn = ConnectHandler(**kwargs) hostname=self.hostname,
try: port=self.port or 22,
return conn.send_command("show running-config") username=self.username,
finally: password=self.password,
conn.disconnect() timeout=_FALLBACK_TIMEOUT,
except Exception as exc: banner_timeout=_FALLBACK_TIMEOUT,
logger.debug( auth_timeout=_FALLBACK_TIMEOUT,
"SSH config fallback (%s) failed for %s: %s", look_for_keys=False,
"legacy" if legacy else "standard", allow_agent=False,
self.hostname, disabled_algorithms=_LEGACY_DISABLED,
exc,
) )
logger.warning("SSH config fallback failed for %s (all transports)", self.hostname) finally:
return "" paramiko.Transport._preferred_kex = orig_kex
_, stdout, _ = client.exec_command("show running-config", timeout=_FALLBACK_TIMEOUT)
config = stdout.read().decode("utf-8", errors="replace")
client.close()
return config
except Exception as exc:
logger.warning("SSH config fallback failed for %s: %s", self.hostname, exc)
return ""
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# NAPALM: get_environment # NAPALM: get_environment