76 lines
3.4 KiB
Python
76 lines
3.4 KiB
Python
upstream: Optional[aiohttp.ClientWebSocketResponse] = None
|
||
session: Optional[ClientSession] = None
|
||
try:
|
||
# Небольшая задержка — Proxmox API иногда возвращает внутреннюю
|
||
# ошибку "name '_client' is not defined" при слишком быстрых
|
||
# последовательных запросах (race в API). 1 секунды обычно хватает.
|
||
if auth_kind == "cookie":
|
||
await asyncio.sleep(1.0)
|
||
|
||
session = ClientSession()
|
||
|
||
# Пробуем WebSocket-handshake с retry на случай race condition в Proxmox API.
|
||
last_exc: Optional[Exception] = None
|
||
for attempt in range(1, 4):
|
||
try:
|
||
resp = await session.get(
|
||
upstream_url,
|
||
headers=headers,
|
||
allow_redirects=False,
|
||
ssl=False if not settings.pve_verify_ssl else None,
|
||
)
|
||
logger.info(
|
||
"console_ws: attempt=%s initial GET status=%s, location=%s, body=%s",
|
||
attempt,
|
||
resp.status,
|
||
resp.headers.get("Location", "<none>"),
|
||
(await resp.text())[:200],
|
||
)
|
||
if resp.status in (301, 302, 303, 307, 308):
|
||
location = resp.headers.get("Location", "")
|
||
upstream_url = _rewrite_redirect(location, fallback_host)
|
||
logger.info("console_ws: rewritten URL to %s", upstream_url)
|
||
await resp.release()
|
||
break
|
||
elif resp.status == 101:
|
||
await resp.release()
|
||
break
|
||
elif resp.status == 502 and "name '_client' is not defined" in (await resp.text()):
|
||
# Известная внутренняя ошибка Proxmox — подождём и повторим.
|
||
await resp.release()
|
||
logger.warning(
|
||
"console_ws: Proxmox вернул race condition 502, "
|
||
"попытка %s/3 через 2с", attempt,
|
||
)
|
||
if attempt < 3:
|
||
await asyncio.sleep(2.0)
|
||
continue
|
||
else:
|
||
body = await resp.text()
|
||
await resp.release()
|
||
raise aiohttp.ClientResponseError(
|
||
request_info=resp.request_info,
|
||
history=resp.history,
|
||
status=resp.status,
|
||
message=body[:120],
|
||
headers=resp.headers,
|
||
)
|
||
except Exception as exc:
|
||
last_exc = exc
|
||
logger.warning("console_ws: attempt %s ошибка: %s", attempt, exc)
|
||
if attempt < 3:
|
||
await asyncio.sleep(2.0)
|
||
continue
|
||
else:
|
||
# Все попытки исчерпаны.
|
||
raise last_exc or RuntimeError("не удалось открыть WebSocket к Proxmox")
|
||
|
||
upstream = await session.ws_connect(
|
||
upstream_url,
|
||
headers=headers,
|
||
ssl=False if not settings.pve_verify_ssl else None,
|
||
autoclose=False,
|
||
autoping=True,
|
||
max_msg_size=8 * 1024 * 1024,
|
||
)
|
||
logger.info("console_ws: upstream connected") |