58dda66f84
Wartungs-Tab im SystemDrawer neu strukturiert: - UPDATES: eine einheitliche Liste (OS, Engine, Hermes-Agent, Modell-Upgrades) mit Status + Aktion-Button, der nur aktiv ist wenn ein Update ansteht (statt Klick-Karten, die sofort updaten). Konsistent mit der Dashboard-UpdatesCard. - DIENSTE: neue Sektion, alle systemd-Units mit Status-Punkt (aus /api/system/services, jetzt inkl. mem0-service) + Restart + Logs-Sprung. - BACKUP: kompakt (letztes Backup + Snapshot-Button + Restore-Hinweis). - GEFAHRENZONE: Reboot abgetrennt. Jobs nur wenn vorhanden. Hermes-Update-Button: POST /api/maintenance/hermes-update -> Job (Backup -> `hermes update --yes` (git pull + deps) -> hermes-gateway restart). Backend: hermes_update_job + USER_SERVICES um mem0-service/hermes-terminal ergaenzt (Restart ging vorher nicht), mem0 in services-API. Live verifiziert: Button hat Hermes d470ed0 -> 3b44a3c aktualisiert, Integration intakt (memory.provider, Plugin laedt), Pre-Update-Backup angelegt, Drawer rendert fehlerfrei. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
1.8 KiB
Python
66 lines
1.8 KiB
Python
"""Wartungs-Endpoints: Update-Badge, OS-/Engine-Update, Reboot, Restart, Logs."""
|
|
|
|
from fastapi import APIRouter, HTTPException, Header
|
|
from pydantic import BaseModel
|
|
|
|
from services import maintenance
|
|
|
|
router = APIRouter(prefix="/api")
|
|
|
|
|
|
class SudoReq(BaseModel):
|
|
sudo_password: str | None = None
|
|
|
|
|
|
class RestartReq(BaseModel):
|
|
service: str
|
|
sudo_password: str | None = None
|
|
|
|
|
|
@router.get("/maintenance/updates")
|
|
def updates() -> dict:
|
|
return maintenance.updates()
|
|
|
|
@router.post("/maintenance/check-updates")
|
|
def check_updates(body: SudoReq) -> dict:
|
|
res = maintenance.check_updates_job(body.sudo_password)
|
|
if isinstance(res, dict) and not res.get("ok", True):
|
|
return res
|
|
return res
|
|
|
|
|
|
@router.post("/maintenance/os-update")
|
|
def os_update(body: SudoReq) -> dict:
|
|
res = maintenance.os_update_job(body.sudo_password)
|
|
if isinstance(res, dict) and not res.get("ok", True):
|
|
return res
|
|
return res
|
|
|
|
|
|
@router.post("/maintenance/engine-update")
|
|
def engine_update(body: SudoReq) -> dict:
|
|
res = maintenance.engine_update_job(body.sudo_password)
|
|
if not res:
|
|
raise HTTPException(400, "Kein Engine-Update-Befehl gesetzt (MC_ENGINE_UPDATE_CMD).")
|
|
return res
|
|
|
|
|
|
@router.post("/maintenance/hermes-update")
|
|
def hermes_update() -> dict:
|
|
return maintenance.hermes_update_job()
|
|
|
|
|
|
@router.post("/maintenance/reboot")
|
|
def reboot(body: SudoReq) -> dict:
|
|
return maintenance.reboot(body.sudo_password)
|
|
|
|
|
|
@router.post("/maintenance/restart")
|
|
def restart(body: RestartReq) -> dict:
|
|
return maintenance.restart_service(body.service, body.sudo_password)
|
|
|
|
|
|
@router.get("/maintenance/logs")
|
|
def logs(service: str, lines: int = 200, x_sudo_password: str | None = Header(None)) -> dict:
|
|
return maintenance.logs(service, lines, x_sudo_password)
|