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:
+47
-19
@@ -590,29 +590,57 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
|
||||
"""Open a one-shot SSH session to retrieve running-config.
|
||||
|
||||
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
|
||||
older ProCurve firmware), then standard. Each attempt is capped at
|
||||
8 seconds so this fallback never pushes the overall poll over budget.
|
||||
Returns empty string on any failure.
|
||||
(e.g. HP 2530 / YA firmware with Mocana SSH).
|
||||
|
||||
Uses paramiko directly (not netmiko) to:
|
||||
- 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
|
||||
for legacy in (True, False):
|
||||
import paramiko
|
||||
|
||||
_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:
|
||||
kwargs = self._netmiko_kwargs(legacy=legacy)
|
||||
kwargs["timeout"] = _FALLBACK_TIMEOUT
|
||||
conn = ConnectHandler(**kwargs)
|
||||
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:
|
||||
return conn.send_command("show running-config")
|
||||
finally:
|
||||
conn.disconnect()
|
||||
except Exception as exc:
|
||||
logger.debug(
|
||||
"SSH config fallback (%s) failed for %s: %s",
|
||||
"legacy" if legacy else "standard",
|
||||
self.hostname,
|
||||
exc,
|
||||
paramiko.Transport._preferred_kex = tuple(_LEGACY_KEX)
|
||||
client.connect(
|
||||
hostname=self.hostname,
|
||||
port=self.port or 22,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
timeout=_FALLBACK_TIMEOUT,
|
||||
banner_timeout=_FALLBACK_TIMEOUT,
|
||||
auth_timeout=_FALLBACK_TIMEOUT,
|
||||
look_for_keys=False,
|
||||
allow_agent=False,
|
||||
disabled_algorithms=_LEGACY_DISABLED,
|
||||
)
|
||||
logger.warning("SSH config fallback failed for %s (all transports)", self.hostname)
|
||||
finally:
|
||||
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 ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user