import docker from fastapi import APIRouter, Depends, Query, HTTPException from config import DOCKER_HOST from rbac import require_admin router = APIRouter() _client = None def get_docker_client(): """Get or create Docker client (lazy initialization).""" global _client if _client is None: _client = docker.DockerClient(base_url=DOCKER_HOST) return _client @router.get("/containers") def list_containers(): client = get_docker_client() return [ { "id": c.short_id, "name": c.name, "status": c.status, "health": (c.attrs.get("State", {}).get("Health", {}) or {}).get("Status", ""), "image": c.image.tags[0] if c.image.tags else str(c.image.id)[:20], "ports": c.ports, } for c in client.containers.list(all=True) ] @router.post("/containers/{container_id}/{action}", dependencies=[Depends(require_admin())]) def container_action(container_id: str, action: str): if action not in ("start", "stop", "restart"): raise HTTPException(status_code=400, detail="Invalid action. Must be one of: start, stop, restart") client = get_docker_client() c = client.containers.get(container_id) getattr(c, action)() return {"ok": True} @router.get("/containers/{container_id}/logs") def container_logs(container_id: str, tail: int = Query(200, le=10000)): client = get_docker_client() c = client.containers.get(container_id) return {"logs": c.logs(tail=tail, timestamps=True).decode(errors="replace")}