6c8b6d81fe
System: services/system.py (psutil CPU/RAM/Disk, sysfs GPU/Temp guarded), routers/system.py GET status + restart (Whitelist) + self-update (systemd- USER, sudo-frei). Connect: services/connect.py (Cline/OpenCode/Zed/Continue/ Claude Code/Memory-MCP → Gateway model:auto, LAN-IP-Override), routers/ connect.py. Frontend: SystemView (Metrik-Bars) + ConnectView (Tool-Tabs, Copy, IP-Override). Lokal verifiziert: Backend-Smoke + Frontend-Build + Browser (System-Bars, Connect-Snippets). Docs aktualisiert (README/STATUS/Plan). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""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}
|