From 38bc4303489c1353f3e246ce17586055d58ca07e Mon Sep 17 00:00:00 2001 From: jeanotx32 Date: Tue, 2 Jun 2026 20:06:39 -0400 Subject: [PATCH] Feat: implement dynamic agent version fetching and update mechanism --- .../backend/__pycache__/main.cpython-313.pyc | Bin 65805 -> 68082 bytes vps-monitor/backend/main.py | 47 ++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/vps-monitor/backend/__pycache__/main.cpython-313.pyc b/vps-monitor/backend/__pycache__/main.cpython-313.pyc index d7fe43533c38dbbf529bc9ae46b5d6901564f0de..a60e5d5befad5b0d9096682c4713a52de57da07b 100644 GIT binary patch delta 16973 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 NKINxUQ8ykm{C`WbJn;Yk delta 14974 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 CpiXH3 diff --git a/vps-monitor/backend/main.py b/vps-monitor/backend/main.py index 4d198f3..ffb0c6a 100644 --- a/vps-monitor/backend/main.py +++ b/vps-monitor/backend/main.py @@ -8,6 +8,7 @@ import asyncio import base64 import json import os +import re import secrets import sqlite3 import time @@ -47,7 +48,18 @@ 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.2.0") + +# Version de référence : d'abord env var explicite, sinon récupérée dynamiquement depuis le dépôt +_FORCED_AGENT_VERSION = os.getenv("EXPECTED_AGENT_VERSION", "") # si non vide, court-circuite le fetch +REPO_AGENT_URL = os.getenv( + "REPO_AGENT_URL", + "https://git.jeanbonapp.com/jeanbon/ScriptVPS/raw/branch/main/vps-monitor/agent/agent.py", +) +_latest_agent_version: str = _FORCED_AGENT_VERSION or "unknown" + + +def _get_expected_version() -> str: + return _latest_agent_version # ─── Ring buffer de stats (en mémoire) ─────────────────────────────────────── _STATS_MAX_POINTS = 120 # 10 min à 5 s d'intervalle @@ -541,8 +553,8 @@ async def fetch_vps_status(vps: dict) -> dict: "system": system, "tags": vps.get("tags", []), "agent_version": agent_version, - "expected_agent_version": EXPECTED_AGENT_VERSION, - "agent_up_to_date": agent_version == EXPECTED_AGENT_VERSION, + "expected_agent_version": _get_expected_version(), + "agent_up_to_date": agent_version == _get_expected_version() and _get_expected_version() != "unknown", } except Exception as e: return { @@ -557,7 +569,7 @@ async def fetch_vps_status(vps: dict) -> dict: "system": None, "tags": vps.get("tags", []), "agent_version": None, - "expected_agent_version": EXPECTED_AGENT_VERSION, + "expected_agent_version": _get_expected_version(), "agent_up_to_date": False, } @@ -614,10 +626,37 @@ async def _stats_collector() -> None: await asyncio.sleep(5) +async def _refresh_latest_agent_version() -> None: + """Récupère AGENT_VERSION depuis le dépôt Gitea toutes les heures. + Si EXPECTED_AGENT_VERSION est défini en env var, cette tâche n'écrase pas la valeur forcée. + """ + global _latest_agent_version + if _FORCED_AGENT_VERSION: + return # version forcée par env var — pas besoin de fetcher + while True: + try: + timeout = aiohttp.ClientTimeout(total=10) + async with aiohttp.ClientSession() as session: + async with session.get(REPO_AGENT_URL, timeout=timeout) as r: + if r.status == 200: + text = await r.text() + m = re.search( + r'^AGENT_VERSION\s*=\s*["\']([^"\']+)["\']', + text, + re.MULTILINE, + ) + if m: + _latest_agent_version = m.group(1) + except Exception: + pass # garder la dernière valeur connue en cas d'erreur réseau + await asyncio.sleep(3600) # rafraîchit toutes les heures + + @app.on_event("startup") async def startup_event() -> None: asyncio.create_task(_stats_collector()) asyncio.create_task(_cleanup_old_stats()) + asyncio.create_task(_refresh_latest_agent_version()) async def _cleanup_old_stats() -> None: