From 209e83044a303a6cd61058944b4428d3bd2c5b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= Date: Sun, 27 Sep 2026 17:32:45 +0900 Subject: [PATCH] =?UTF-8?q?=D0=AD=D0=BA=D1=80=D0=B0=D0=BD=20=D0=BC=D0=B0?= =?UTF-8?q?=D1=88=D0=B8=D0=BD=D1=8B=20=D1=81=D0=BD=D0=BE=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F:=20noVNC=201.6=20=D1=81=D1=82=D1=80=D0=BE=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=B4=D1=80=D0=B5=D1=81=20WebSocket=20=D0=BE?= =?UTF-8?q?=D1=82=20=D1=81=D0=B2=D0=BE=D0=B5=D0=B9=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=86=D1=8B=20=D0=B8=20=D1=83=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D0=BB=20=D0=B2=20/novnc/console/ws,=20=D0=BF=D1=83?= =?UTF-8?q?=D1=82=D1=8C=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=B8=20=D1=81=20?= =?UTF-8?q?1.6,=20=D0=B8=20=D1=81=201.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_app.py | 17 +++++++++++++++++ web/app.py | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_app.py b/tests/test_app.py index 398b286..60e4a50 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -254,3 +254,20 @@ def test_failed_create_of_existing_vm_keeps_its_disk(logged_in, data_dirs): def test_operation_page_reveals_only_buttons_for_its_result(): script = (Path(__file__).resolve().parents[1] / "web" / "static" / "panel.js").read_text() assert '$$(`[data-op-done="${status}"]`)' in script and "$$('[data-op-done]')" not in script + + +def test_console_websocket_path_works_with_old_and_new_novnc(tmp_path, monkeypatch): + """noVNC 1.6 (Ubuntu 26.04) считает path от /novnc/vnc.html: без "../" экран стучался в /novnc/console/ws/… и не подключался.""" + import posixpath + from urllib.parse import parse_qs, urljoin, urlsplit + + (tmp_path / "vnc.html").write_text("") + monkeypatch.setattr(app, "NOVNC_DIR", tmp_path) + monkeypatch.setattr(app, "vm_vnc_display", lambda name: "127.0.0.1:0") + info = app.console_info("web01") + page = "https://panel.test:8443" + info["url"] + path = parse_qs(urlsplit(page).query)["path"][0] + token = path.rsplit("/", 1)[1] + assert app.console_serializer.loads(token) == {"vm": "web01", "port": 5900} + assert urlsplit(urljoin(page, path)).path == f"/console/ws/{token}" # noVNC 1.6: new URL(path, location.href) + assert posixpath.normpath("/" + path) == f"/console/ws/{token}" # noVNC 1.3: "wss://host:port/" + path diff --git a/web/app.py b/web/app.py index 87557af..9d172a3 100644 --- a/web/app.py +++ b/web/app.py @@ -939,7 +939,9 @@ def console_info(name: str) -> dict[str, Any]: url = None if port and has_novnc: token = console_serializer.dumps({"vm": name, "port": port}) - url = f"/novnc/vnc.html?autoconnect=1&resize=scale&path=console/ws/{token}" + # "../": noVNC 1.6 (Ubuntu 26.04) строит адрес от своей страницы /novnc/vnc.html, а 1.3 (Ubuntu 24.04) + # приклеивает path к корню сайта; в обоих случаях получается /console/ws/<токен>. + url = f"/novnc/vnc.html?autoconnect=1&resize=scale&path=../console/ws/{token}" return {"vm": name, "display": display, "port": port, "has_novnc": has_novnc, "novnc_dir": str(NOVNC_DIR) if NOVNC_DIR else "not installed", "url": url}