connectiopn fix round 2 2
This commit is contained in:
53
README.md
53
README.md
@ -636,3 +636,56 @@ ist die massgebliche, aktuelle Fassung dieser Liste. Kurzfassung:
|
||||
sollten das Problem loesen, sollten aber nach dem Deployment einmal
|
||||
manuell im Browser bestaetigt werden.
|
||||
</content>
|
||||
|
||||
## Phase 14: `get_server_host_key()` kennt kein `connect_timeout`
|
||||
|
||||
**Meldung:** `Host-Key konnte nicht ermittelt werden -- Ziel nicht erreichbar:
|
||||
get_server_host_key() got an unexpected keyword argument 'connect_timeout'`,
|
||||
und zwar in **unter einer Sekunde** nach dem Klick auf "Host-Key ermitteln".
|
||||
|
||||
**Ursache:** `asyncssh.get_server_host_key()` nimmt -- anders als
|
||||
`asyncssh.connect()` -- **kein `**kwargs`** entgegen. Seine Parameterliste ist
|
||||
in asyncssh 2.18.0 abschliessend (`host, port, tunnel, proxy_command, family,
|
||||
flags, local_addr, sock, client_version, kex_algs, server_host_key_algs,
|
||||
config, options`); `connect_timeout` gehoert **nicht** dazu. Nur
|
||||
`asyncssh.connect()` reicht unbekannte Argumente ueber `**kwargs` an
|
||||
`SSHClientConnectionOptions` weiter -- deshalb war `connect_timeout=10` dort
|
||||
korrekt und hier ein sofortiger `TypeError`, noch bevor ein Socket geoeffnet
|
||||
wurde. Daher die Reaktionszeit von unter einer Sekunde: es gab nie einen
|
||||
Verbindungsversuch.
|
||||
|
||||
Der Fehler stammt aus Phase 12 und betraf **beide** Aufrufstellen in
|
||||
`app/ssh_proxy/proxy.py`: `discover_and_store_host_key()` (Knopf "Host-Key
|
||||
ermitteln") und `_verified_host_key()` -- letzteres liegt im regulaeren
|
||||
Verbindungspfad, es war also **jede** SSH-Sitzung betroffen, nicht nur die
|
||||
Ermittlung.
|
||||
|
||||
**Warum es dreimal falsch diagnostiziert wurde:** anfangs lief der `TypeError`
|
||||
unbehandelt bis FastAPI -> nackter HTTP 500 ohne Wortlaut. Der Nachtrag zu
|
||||
Phase 12 deutete diesen 500er als zu enges `except (asyncssh.Error, OSError)`
|
||||
und verbreiterte auf `except Exception`. Damit wurde der `TypeError` zwar
|
||||
gefangen -- aber als `HostKeyDiscoveryError` und damit als "Ziel nicht
|
||||
erreichbar" **verkleidet**. Die Tests aus Phase 12 konnten es nicht sehen,
|
||||
weil ihre asyncssh-Attrappen als `(host, port=22, **kw)` definiert waren und
|
||||
jedes beliebige Argument klaglos schluckten.
|
||||
|
||||
**Loesung**
|
||||
* Neuer Helfer `_fetch_server_host_key(address, port)` in `proxy.py`: ruft
|
||||
`asyncssh.get_server_host_key(address, port=port)` auf und setzt das
|
||||
Zeitlimit von aussen ueber `asyncio.wait_for()`
|
||||
(`HOST_KEY_CONNECT_TIMEOUT = 10`). Damit ist der Aufruf unabhaengig davon,
|
||||
wie einzelne asyncssh-Versionen ihre Optionen benennen.
|
||||
* Beide Aufrufstellen benutzen den Helfer. Ein `asyncio.TimeoutError` wird als
|
||||
`HostKeyDiscoveryError` mit Klartext "Zeitlimit von 10s ueberschritten"
|
||||
gemeldet.
|
||||
* **Ein `TypeError` wird ausdruecklich NICHT mehr maskiert**, sondern
|
||||
durchgereicht (und mit vollem Traceback geloggt): ein Aufruffehler im
|
||||
eigenen Code darf nicht als Netzwerkproblem erscheinen. Genau diese
|
||||
Maskierung hat die Fehlersuche zweimal in die falsche Richtung geschickt.
|
||||
Alle uebrigen Fehler dieses einen externen Aufrufs bleiben wie bisher breit
|
||||
gefangen.
|
||||
* `tests/test_phase12.py`: die Attrappen haben jetzt **kein** `**kw` mehr.
|
||||
* `tests/test_phase14.py` (8 Faelle), u.a. ein Test, der per
|
||||
`inspect.signature(asyncssh.get_server_host_key).bind(...)` gegen das
|
||||
**tatsaechlich installierte** asyncssh prueft -- der haette den Bug im
|
||||
Produktivsystem gefunden.
|
||||
|
||||
Reference in New Issue
Block a user