"""System-Endpoints: Live-Status + Wartung (Restart/Self-Update — auf der Box). Wartung läuft als systemd-USER-Dienst → KEIN sudo/Passwort (Nordstern). Lokal (Windows) schlagen die Shell-Befehle harmlos fehl und werden als Fehler zurückgegeben statt zu crashen. """ import os import subprocess from fastapi import APIRouter, HTTPException from pydantic import BaseModel from services.system import system_status router = APIRouter(prefix="/api") # Nur diese User-Dienste dürfen neugestartet werden. ALLOWED_SERVICES = {"mission-control-2", "litellm-gateway", "hermes-webui"} # Quelle für Self-Update (auf der Box ~/mission-control-v2). SOURCE_DIR = os.path.expanduser(os.environ.get("MC2_SOURCE_DIR", "~/mission-control-v2")) @router.get("/system/status") def status() -> dict: return system_status() def _run(cmd: list[str], cwd: str | None = None) -> dict: try: p = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=180) return {"ok": p.returncode == 0, "code": p.returncode, "out": (p.stdout or "")[-2000:], "err": (p.stderr or "")[-2000:]} except Exception as exc: # noqa: BLE001 return {"ok": False, "code": -1, "out": "", "err": str(exc)} class RestartReq(BaseModel): service: str @router.post("/system/restart") def restart(req: RestartReq) -> dict: if req.service not in ALLOWED_SERVICES: raise HTTPException(400, f"Dienst '{req.service}' nicht erlaubt.") return _run(["systemctl", "--user", "restart", req.service]) @router.post("/system/self-update") def self_update() -> dict: """git pull (Source) → venv-Deps → Dienst-Restart. Auf der Box; lokal Fehler.""" pull = _run(["git", "fetch", "--all"], cwd=SOURCE_DIR) reset = _run(["git", "reset", "--hard", "origin/main"], cwd=SOURCE_DIR) restart_res = _run(["systemctl", "--user", "restart", "mission-control-2"]) return {"pull": pull, "reset": reset, "restart": restart_res}