diff --git a/vps-monitor/.pids b/vps-monitor/.pids index c191dd7..f2b7530 100644 --- a/vps-monitor/.pids +++ b/vps-monitor/.pids @@ -1,2 +1,2 @@ -80001 -80063 +83491 +83555 diff --git a/vps-monitor/agent/agent.py b/vps-monitor/agent/agent.py index 0a3cbc9..a07a53a 100644 --- a/vps-monitor/agent/agent.py +++ b/vps-monitor/agent/agent.py @@ -19,7 +19,7 @@ from fastapi.security import APIKeyHeader # ─── Config ─────────────────────────────────────────────────────────────────── -AGENT_VERSION = "1.1.0" +AGENT_VERSION = "1.2.0" REPO_BASE = os.getenv("AGENT_REPO_BASE", "https://git.jeanbonapp.com/jeanbon/ScriptVPS/raw/branch/main") INSTALL_DIR = os.getenv("AGENT_INSTALL_DIR", "/opt/vps-monitor-agent") @@ -219,6 +219,46 @@ def compose_update(project: str, _: None = Depends(require_api_key)): return {"output": output, "project": project, "working_dir": working_dir} +@app.get("/services") +def list_services(_: None = Depends(require_api_key)): + """Retourne la liste des services systemd (hors Docker) avec leur état.""" + try: + result = subprocess.run( + ["systemctl", "list-units", "--type=service", "--no-legend", "--no-pager", "--all"], + capture_output=True, text=True, timeout=10, + ) + except FileNotFoundError: + raise HTTPException(status_code=501, detail="systemctl introuvable — système non-systemd") + except subprocess.TimeoutExpired: + raise HTTPException(status_code=504, detail="systemctl a expiré") + + _DOCKER_SERVICES = {"docker.service", "containerd.service", "docker.socket"} + + services = [] + for line in result.stdout.strip().splitlines(): + # Supprime les puces (● ○) et les espaces de début + line = line.lstrip("●○").strip() + if not line: + continue + parts = line.split(None, 4) + if len(parts) < 4: + continue + name = parts[0] + if not name.endswith(".service"): + continue + if name.lower() in _DOCKER_SERVICES or name.lower().startswith("docker"): + continue + services.append({ + "name": name, + "load": parts[1], + "active": parts[2], + "sub": parts[3], + "description": parts[4].strip() if len(parts) > 4 else "", + }) + + return sorted(services, key=lambda s: s["name"]) + + # ─── Entrée ─────────────────────────────────────────────────────────────────── if __name__ == "__main__": diff --git a/vps-monitor/backend/__pycache__/main.cpython-313.pyc b/vps-monitor/backend/__pycache__/main.cpython-313.pyc index af6dd08..d7fe435 100644 Binary files a/vps-monitor/backend/__pycache__/main.cpython-313.pyc and b/vps-monitor/backend/__pycache__/main.cpython-313.pyc differ diff --git a/vps-monitor/backend/main.py b/vps-monitor/backend/main.py index e6118dc..4d198f3 100644 --- a/vps-monitor/backend/main.py +++ b/vps-monitor/backend/main.py @@ -47,7 +47,7 @@ from webauthn.helpers.structs import ( # ─── Config ─────────────────────────────────────────────────────────────────── DB_FILE = Path(os.getenv("DB_FILE", "data/monitor.db")) -EXPECTED_AGENT_VERSION = os.getenv("EXPECTED_AGENT_VERSION", "1.1.0") +EXPECTED_AGENT_VERSION = os.getenv("EXPECTED_AGENT_VERSION", "1.2.0") # ─── Ring buffer de stats (en mémoire) ─────────────────────────────────────── _STATS_MAX_POINTS = 120 # 10 min à 5 s d'intervalle @@ -498,6 +498,12 @@ async def fetch_vps_status(vps: dict) -> dict: try: containers_res = await agent_get(vps, "/containers") + # Services systemd (non-Docker) — optionnel, agent >= 1.2.0 + try: + services_res = await agent_get(vps, "/services") + except Exception: + services_res = [] + # Source unique : ring buffer → carte et modal affichent exactement la même valeur history = _stats_history.get(vps["id"]) if history: @@ -531,6 +537,7 @@ async def fetch_vps_status(vps: dict) -> dict: "description": vps.get("description", ""), "online": True, "containers": containers_res, + "services": services_res, "system": system, "tags": vps.get("tags", []), "agent_version": agent_version, @@ -546,6 +553,7 @@ async def fetch_vps_status(vps: dict) -> dict: "online": False, "error": str(e), "containers": [], + "services": [], "system": None, "tags": vps.get("tags", []), "agent_version": None, diff --git a/vps-monitor/frontend/src/components/VpsCard.jsx b/vps-monitor/frontend/src/components/VpsCard.jsx index 6b149b0..2d4c3e1 100644 --- a/vps-monitor/frontend/src/components/VpsCard.jsx +++ b/vps-monitor/frontend/src/components/VpsCard.jsx @@ -1,4 +1,4 @@ -import { Server, Wifi, WifiOff, Trash2, ChevronDown, ChevronUp, RefreshCw, Cpu, MemoryStick, ArrowUp, ArrowDown, Pencil, BarChart2, CloudDownload, Copy, Check } from 'lucide-react' +import { Server, Wifi, WifiOff, Trash2, ChevronDown, ChevronUp, RefreshCw, Cpu, MemoryStick, ArrowUp, ArrowDown, Pencil, BarChart2, CloudDownload, Copy, Check, Activity } from 'lucide-react' import { useState } from 'react' import ContainerRow from './ContainerRow' import { tagColor } from './TagInput' @@ -19,6 +19,7 @@ export default function VpsCard({ vps, onAction, onLogs, onDelete, onUpdate, onE const [updatingProject, setUpdatingProject] = useState(null) const [updatingAgent, setUpdatingAgent] = useState(false) const [exported, setExported] = useState(false) + const [servicesExpanded, setServicesExpanded] = useState(false) const handleExport = async () => { await onExport(vps.id) @@ -208,6 +209,46 @@ export default function VpsCard({ vps, onAction, onLogs, onDelete, onUpdate, onE
{vps.description}
)} + {/* Services systemd */} + {!collapsed && vps.online && vps.services?.length > 0 && ( +