fix(get_config): use SSHClient.connect() without algorithm overrides
The SSH console link works on this switch using plain paramiko SSHClient.connect() with no disabled_algorithms and no Transport hacks. Our previous approaches (Transport._preferred_kex, socket-level timeout) were breaking the negotiation. Revert to the simple approach that works.
This commit is contained in:
+18
-36
@@ -592,50 +592,32 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
|
|||||||
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 with Mocana SSH).
|
(e.g. HP 2530 / YA firmware with Mocana SSH).
|
||||||
|
|
||||||
Uses a raw socket with settimeout() so the timeout covers ALL phases of
|
Uses SSHClient.connect() with the same approach as the netOrk SSH
|
||||||
the SSH handshake (TCP connect, banner, KEX, auth) — not just TCP connect.
|
console link (_paramiko_connect in _helpers.py) — no algorithm
|
||||||
This is the only reliable way to prevent a hanging KEX from blocking
|
overrides, plain password auth, 15-second banner timeout.
|
||||||
indefinitely inside the poll task.
|
|
||||||
"""
|
"""
|
||||||
import socket as _socket
|
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
|
|
||||||
_FALLBACK_TIMEOUT = 8 # seconds — covers the entire SSH session
|
_TIMEOUT = 15
|
||||||
|
|
||||||
_LEGACY_KEX = [
|
|
||||||
"diffie-hellman-group1-sha1",
|
|
||||||
"diffie-hellman-group14-sha1",
|
|
||||||
"diffie-hellman-group14-sha256",
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock = _socket.create_connection(
|
client = paramiko.SSHClient()
|
||||||
(self.hostname, self.port or 22),
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
timeout=_FALLBACK_TIMEOUT,
|
client.connect(
|
||||||
)
|
hostname=self.hostname,
|
||||||
sock.settimeout(_FALLBACK_TIMEOUT) # applies to all recv/send including KEX
|
port=self.port or 22,
|
||||||
|
|
||||||
transport = paramiko.Transport(sock)
|
|
||||||
transport.get_security_options().kex = _LEGACY_KEX
|
|
||||||
transport.connect(
|
|
||||||
username=self.username,
|
username=self.username,
|
||||||
password=self.password,
|
password=self.password,
|
||||||
|
timeout=_TIMEOUT,
|
||||||
|
banner_timeout=_TIMEOUT,
|
||||||
|
auth_timeout=_TIMEOUT,
|
||||||
|
look_for_keys=False,
|
||||||
|
allow_agent=False,
|
||||||
)
|
)
|
||||||
|
_, stdout, _ = client.exec_command("show running-config", timeout=_TIMEOUT)
|
||||||
channel = transport.open_session()
|
config = stdout.read().decode("utf-8", errors="replace")
|
||||||
channel.settimeout(_FALLBACK_TIMEOUT)
|
client.close()
|
||||||
channel.exec_command("show running-config")
|
return config
|
||||||
|
|
||||||
chunks: list[bytes] = []
|
|
||||||
while True:
|
|
||||||
data = channel.recv(4096)
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
chunks.append(data)
|
|
||||||
|
|
||||||
transport.close()
|
|
||||||
return b"".join(chunks).decode("utf-8", errors="replace")
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("SSH config fallback failed for %s: %s", self.hostname, exc)
|
logger.warning("SSH config fallback failed for %s: %s", self.hostname, exc)
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user