"""Host / Docker system information.""" from __future__ import annotations import os import shutil from fastapi import APIRouter, Depends from auth import get_current_user from config import settings from docker_client import DockerError, get_client, safe_call from models.user import User router = APIRouter(prefix="/api/system", tags=["system"]) def _read_proc(path: str) -> str: full = os.path.join(settings.HOST_PROC_PATH, path) if not os.path.isfile(full): full = os.path.join("/proc", path) try: with open(full, "r", encoding="utf-8") as fh: return fh.read() except OSError: return "" def _mem_info() -> dict: info = {} for line in _read_proc("meminfo").splitlines(): parts = line.split(":") if len(parts) == 2: key = parts[0].strip() val = parts[1].strip().split()[0] try: info[key] = int(val) * 1024 # kB -> bytes except ValueError: pass total = info.get("MemTotal", 0) available = info.get("MemAvailable", info.get("MemFree", 0)) return {"total": total, "available": available, "used": max(total - available, 0)} def _uptime() -> float: raw = _read_proc("uptime") try: return float(raw.split()[0]) except (IndexError, ValueError): return 0.0 def _cpu_count() -> int: return os.cpu_count() or 0 def _disk_usage() -> dict: try: usage = shutil.disk_usage(settings.DATA_DIR) return {"total": usage.total, "used": usage.used, "free": usage.free} except OSError: return {"total": 0, "used": 0, "free": 0} @router.get("/info") def system_info(_user: User = Depends(get_current_user)) -> dict: docker_version = "" host_os = "" containers_running = 0 containers_total = 0 try: client = get_client() version = safe_call(client.version) docker_version = version.get("Version", "") info = safe_call(client.info) host_os = info.get("OperatingSystem", "") containers_running = info.get("ContainersRunning", 0) containers_total = info.get("Containers", 0) except DockerError as exc: docker_version = f"unavailable ({exc.error})" return { "docker_version": docker_version, "host_os": host_os, "hostname": os.uname().nodename, "cpu_cores": _cpu_count(), "ram": _mem_info(), "disk": _disk_usage(), "uptime_seconds": _uptime(), "containers_running": containers_running, "containers_total": containers_total, "gpus": [], # populated in Phase 2 }