diff --git a/apps/tesm/pyproject.toml b/apps/tesm/pyproject.toml index b5c463c..59a6c4e 100644 --- a/apps/tesm/pyproject.toml +++ b/apps/tesm/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tesm" -version = "2.8.28" +version = "2.8.29" description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen" requires-python = ">=3.11" dependencies = [ diff --git a/deploy/install.sh b/deploy/install.sh index 3a50bec..7578e62 100644 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -418,9 +418,32 @@ info "Dateien abgeglichen (Instanzdaten unter data/ bleiben unangetastet)" # -- venv -------------------------------------------------------------------- step "Python-Umgebung" -if [[ ! -x "$ROOT/venv/bin/python3" ]]; then +# Ein venv haengt an der **Minor-Fassung**, mit der er gebaut wurde: die Pakete +# liegen unter lib/python3.X. Wechselt die Systemfassung -- ein Release-Upgrade +# von Ubuntu bringt genau das, 24.04 hat 3.12 und 26.04 hat 3.14 --, dann ist +# venv/bin/python3 weiter ausfuehrbar: der Verweis zeigt auf /usr/bin/python3, +# also auf den **neuen** Interpreter. Der venv sieht heil aus und ist es nicht. +# Er findet danach kein einziges Paket mehr, nicht einmal pip. +# +# Gemessen auf dem Testserver, mit verschobenem lib-Verzeichnis: +# [[ -x venv/bin/python3 ]] -> wahr +# venv/bin/python3 -m pip --version -> "No module named pip" +# +# Die alte Pruefung fragte nur nach der Ausfuehrbarkeit. Sie haette den toten +# venv behalten und waere eine Zeile spaeter an "python3 -m pip" gescheitert -- +# mitten in einer Aktualisierung, auf einem Server, dessen Dienste ohnehin +# schon stehen. Gefragt wird deshalb, was gebraucht wird: laesst sich in +# diesem venv pip benutzen? +venv_traegt() { + [[ -x "$ROOT/venv/bin/python3" ]] || return 1 + "$ROOT/venv/bin/python3" -c "import pip" >/dev/null 2>&1 +} +if ! venv_traegt; then + # Ohne --clear: ein erneutes "venv" ergaenzt das fehlende lib-Verzeichnis und + # holt pip zurueck; die Abhaengigkeiten kommen gleich darunter ohnehin neu. + # Auch das ist gemessen und nicht angenommen. python3 -m venv "$ROOT/venv" - info "venv erzeugt" + info "Python-Umgebung aufgebaut ($(python3 -V 2>&1))" fi # Immer ueber "python3 -m pip" -- der pip-Shim im venv baeckt einen absoluten # Pfad in seinen Shebang, der nach einer Umbenennung des Verzeichnisses bricht. diff --git a/packages/tesm-core/pyproject.toml b/packages/tesm-core/pyproject.toml index 2fee753..b9c4fca 100644 --- a/packages/tesm-core/pyproject.toml +++ b/packages/tesm-core/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tesm-core" -version = "2.8.16" +version = "2.8.17" description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver" requires-python = ">=3.11" dependencies = [ diff --git a/packages/tesm-core/src/tesm_core/cli_web.py b/packages/tesm-core/src/tesm_core/cli_web.py index 38b9c53..4262bee 100644 --- a/packages/tesm-core/src/tesm_core/cli_web.py +++ b/packages/tesm-core/src/tesm_core/cli_web.py @@ -42,6 +42,8 @@ def _config_from_settings(extension: Any, conn: Any) -> webserver.WebConfig: ], ) return webserver.WebConfig( + # Die neue Schreibweise, sobald der Webserver sie kennt. + http2_directive=webserver.nginx_kann_http2(), app_key=extension.config.site_key, upstream=str(extension.registry.get("upstream", "127.0.0.1:5000")), static_root=str( diff --git a/packages/tesm-core/src/tesm_core/system/webserver.py b/packages/tesm-core/src/tesm_core/system/webserver.py index 1ae1ac1..4821b92 100644 --- a/packages/tesm-core/src/tesm_core/system/webserver.py +++ b/packages/tesm-core/src/tesm_core/system/webserver.py @@ -58,8 +58,14 @@ class WebConfig: #: ``listen ... ssl http2;`` und weisen die neue Direktive mit #: "unknown directive" ab -- der ganze Webserver startet dann nicht mehr. #: Auf POETEST (nginx 1.24) genau so passiert. Vorgabe ist deshalb die alte - #: Schreibweise: sie funktioniert ueberall und erzeugt auf neuen Versionen - #: nur eine Warnung. + #: Schreibweise: sie funktioniert ueberall. + #: + #: Wer die Konfiguration erzeugt, fragt vorher ``nginx_kann_http2()`` -- + #: dann steht auf einem neuen Webserver auch die neue Schreibweise. Das ist + #: nicht nur Kosmetik gegen eine Warnung: nginx hat die alte Form als + #: veraltet erklaert, und was veraltet ist, faellt irgendwann weg. Ein + #: Release-Upgrade von Ubuntu ist genau der Moment, in dem so etwas + #: unbemerkt naeherrueckt (24.04 hat nginx 1.24, 26.04 hat 1.28). http2_directive: bool = False @property @@ -89,6 +95,47 @@ class WebConfig: return "" if self.https_port == 443 else f":{self.https_port}" +#: Ab dieser Fassung kennt nginx ``http2 on;``. +HTTP2_DIREKTIVE_AB = (1, 25, 1) + + +def fassung_aus_ausgabe(text: str) -> tuple[int, ...]: + """``nginx version: nginx/1.28.3 (Ubuntu)`` -> ``(1, 28, 3)``. + + Getrennt vom Aufruf, damit sich die Entscheidung pruefen laesst, ohne + einen Webserver zu installieren. Was nicht ins Muster passt, ergibt ein + leeres Tupel -- und damit die Schreibweise, die ueberall funktioniert. + """ + treffer = re.search(r"nginx/(\d+)\.(\d+)\.(\d+)", text or "") + return tuple(int(teil) for teil in treffer.groups()) if treffer else () + + +def nginx_version() -> tuple[int, ...]: + """Die Fassung des installierten nginx, sonst ein leeres Tupel. + + ``nginx -v`` schreibt nach stderr und braucht keine Rechte. Faellt die + Antwort aus -- kein nginx, kein Ausfuehrungsrecht, fremdes Format --, gibt + es hier nichts zu raten. + """ + import shutil + import subprocess + + pfad = shutil.which("nginx") or "/usr/sbin/nginx" + try: + fertig = subprocess.run( + [pfad, "-v"], capture_output=True, text=True, timeout=5, check=False + ) + except (OSError, subprocess.SubprocessError): + return () + return fassung_aus_ausgabe(fertig.stderr + fertig.stdout) + + +def nginx_kann_http2() -> bool: + """Versteht der installierte nginx ``http2 on;``?""" + fassung = nginx_version() + return bool(fassung) and fassung >= HTTP2_DIREKTIVE_AB + + def validate_domain(value: str) -> str: text = (value or "").strip().lower().rstrip(".") if not text: diff --git a/packages/tesm-core/src/tesm_core/views/hostsettings.py b/packages/tesm-core/src/tesm_core/views/hostsettings.py index d3424a3..263dc46 100644 --- a/packages/tesm-core/src/tesm_core/views/hostsettings.py +++ b/packages/tesm-core/src/tesm_core/views/hostsettings.py @@ -204,6 +204,8 @@ def _web_config() -> webserver.WebConfig: ], ) return webserver.WebConfig( + # Die neue Schreibweise, sobald der Webserver sie kennt. + http2_directive=webserver.nginx_kann_http2(), app_key=extension.config.site_key, upstream=str(extension.registry.get("upstream", "127.0.0.1:5000")), static_root=str(extension.registry.get("static_root", extension.config.base_dir / "static")),