fix(admin): Phase 0 — Log & Restart reparieren, Status auf Wahrheit

Wurzel-Ursache: Dienst läuft als System-Dienst, Code nutzte aber
systemctl/journalctl --user → Log leer, Restart wirkungslos.

- Log-WS (admin.py): --user → System-journalctl. Erfordert voice in
  Gruppe systemd-journal (siehe DEPLOYMENT.md 2.7.1).
- Restart (admin_llm.py): --user → sudo -n systemctl restart über eng
  begrenzte sudoers-Regel; is-active ebenfalls auf System-Dienst.
- Status (app.js): irrelevante Ollama/llama.cpp-Karte + Backend-Wechsel
  entfernt; zeigt jetzt echtes aktives LLM-Modell (aus Runtime-Config);
  Neustart in eigener "Wartung"-Karte (zieht in Phase 3 nach Konfiguration).
- DEPLOYMENT.md 2.7.1: sudoers-Regel + journal-Gruppe dokumentiert.

Live verifiziert: Log lesbar, Restart ohne Passwort, /health nach 3s zurück.
Tests: 214 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 02:27:18 +02:00
commit f3f9151894
4 changed files with 58 additions and 90 deletions

View file

@ -1,6 +1,6 @@
"""Read-only Statusabfragen rund um das lokale LLM-Backend (fuer das Admin-Panel).
Alles nur lesend, ohne sudo: `docker ps`, `ollama ps`, `nvidia-smi`, `systemctl --user`.
Status-Abfragen sind read-only: `docker ps`, `ollama ps`, `nvidia-smi`, `systemctl is-active`.
Fehlende Tools oder Fehler fuehren zu sicheren Defaults (None/[]), nie zu Exceptions.
"""
@ -97,7 +97,7 @@ async def _gpus() -> list[dict]:
async def _gateway_service_active() -> bool:
out = await _run(["systemctl", "--user", "is-active", "voice-assistant.service"], timeout=4.0)
out = await _run(["systemctl", "is-active", "voice-assistant.service"], timeout=4.0)
return bool(out and out.strip() == "active")
@ -177,11 +177,13 @@ async def switch_backend(backend: str, model: str | None = None) -> dict:
def restart_gateway_detached() -> dict:
"""Startet das Gateway als systemd-User-Dienst neu (losgelöst, Self-Restart-sicher)."""
xdg = os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")
"""Startet das Gateway (System-Dienst) neu — losgelöst, Self-Restart-sicher.
Nutzt eine eng begrenzte sudo-Regel (/etc/sudoers.d/voice-assistant):
`voice ALL=(root) NOPASSWD: /usr/bin/systemctl restart voice-assistant.service`.
"""
subprocess.Popen(
["bash", "-c",
f"sleep 1; XDG_RUNTIME_DIR={xdg} systemctl --user restart voice-assistant.service"],
["bash", "-c", "sleep 1; sudo -n systemctl restart voice-assistant.service"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True,