From 1a93caf62de3ebe66fee678b17f38f89d21a652b Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Fri, 20 Feb 2026 10:31:18 +0800 Subject: [PATCH] feat: add container monitor & telegram alerts Added asyncio monitoring task to main.py to watch Docker container state transitions and send Telegram notifications on failures. --- dashboard/backend/config.py | 4 ++++ dashboard/backend/main.py | 37 +++++++++++++++++++++++++++++ dashboard/backend/routers/system.py | 4 +--- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/dashboard/backend/config.py b/dashboard/backend/config.py index 61c98dc..82f629b 100644 --- a/dashboard/backend/config.py +++ b/dashboard/backend/config.py @@ -23,3 +23,7 @@ SSH_KEY_PATH = os.environ.get("SSH_KEY_PATH", "/app/ssh/id_ed25519") VPS_SSH_HOST = os.environ.get("VPS_SSH_HOST", "158.101.140.85") VPS_SSH_USER = os.environ.get("VPS_SSH_USER", "jimmyg") VPS_SSH_KEY_PATH = os.environ.get("VPS_SSH_KEY_PATH", "/app/ssh/vps_id_ed25519") + +# Telegram notifications +TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "") +TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "") diff --git a/dashboard/backend/main.py b/dashboard/backend/main.py index ee892bb..52bea23 100644 --- a/dashboard/backend/main.py +++ b/dashboard/backend/main.py @@ -3,8 +3,45 @@ from fastapi.staticfiles import StaticFiles from routers import docker_router, gitea, files, terminal, system, auth import auth as auth_module +import asyncio +import httpx +from config import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID + app = FastAPI(title="NAS Dashboard") +async def monitor_containers(): + import docker + from config import DOCKER_HOST + client = docker.DockerClient(base_url=DOCKER_HOST) + + # Store initial states + previous_states = {} + + while True: + try: + for c in client.containers.list(all=True): + current_status = c.status + if c.id in previous_states: + prev_status = previous_states[c.id] + # Alert if it transitioned from running to exited or unhealthy + if prev_status == "running" and current_status in ("exited", "dead"): + msg = f"⚠️ *Container Alert* ⚠️\nContainer `{c.name}` just stopped unexpectedly (Status: {current_status})." + # Use httpx directly as system.send_notification expects a FastAPI request object usually + if TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID: + async with httpx.AsyncClient() as hc: + await hc.post( + f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage", + data={"chat_id": TELEGRAM_CHAT_ID, "text": msg, "parse_mode": "Markdown"}, + ) + previous_states[c.id] = current_status + except Exception as e: + print(f"Error in container monitor: {e}") + + await asyncio.sleep(60) + +@app.on_event("startup") +async def startup_event(): + asyncio.create_task(monitor_containers()) # Public auth endpoints app.include_router(auth.router, prefix="/api/auth", tags=["auth"]) diff --git a/dashboard/backend/routers/system.py b/dashboard/backend/routers/system.py index ec193af..0539b5d 100644 --- a/dashboard/backend/routers/system.py +++ b/dashboard/backend/routers/system.py @@ -5,12 +5,10 @@ import platform import time import httpx from fastapi import APIRouter +from config import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID router = APIRouter() -TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "") -TELEGRAM_CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "") - @router.post("/notify") async def send_notification(body: dict):