From 099609fa2909e5264900a874cb29601effd2acdc Mon Sep 17 00:00:00 2001 From: "info@pi-farm.de" Date: Fri, 6 Mar 2026 10:33:59 +0000 Subject: [PATCH] main.py aktualisiert --- main.py | 116 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/main.py b/main.py index 299dc2f..ef8314c 100644 --- a/main.py +++ b/main.py @@ -15,6 +15,7 @@ from fastapi import FastAPI, WebSocket, BackgroundTasks, Request, Form, WebSocke from fastapi.responses import RedirectResponse from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles +from contextlib import asynccontextmanager from dotenv import load_dotenv, set_key # Lade Umgebungsvariablen aus der .env Datei @@ -176,34 +177,47 @@ async def bootstrap_ssh_only(ip, user, password, sudo_pass=""): await manager.broadcast(f"✅ Node {ip} verbunden und analysiert.") # --- AUTO-REFRESH (Alle 60 Sekunden) --- -@app.on_event("startup") -async def start_auto_refresh(): - asyncio.create_task(auto_refresh_loop()) +@asynccontextmanager +async def lifespan(app: FastAPI): + # Alles hier drin läuft beim Starten + refresh_task = asyncio.create_task(auto_refresh_loop()) + yield + # Alles hier drin läuft beim Beenden + refresh_task.cancel() + +app = FastAPI(lifespan=lifespan) async def auto_refresh_loop(): + print("🚀 Auto-Refresh Task gestartet...") while True: - await asyncio.sleep(60) # Alle 60 Sekunden - conn = get_db() - nodes = conn.execute('SELECT id, ip FROM nodes').fetchall() - conn.close() - - for n in nodes: - # 1. Schneller Ping-Check, um lange SSH-Timeouts bei Offline-Nodes zu vermeiden - proc = await asyncio.create_subprocess_exec( - "ping", "-c", "1", "-W", "1", n['ip'], - stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL - ) - await proc.wait() + try: + conn = get_db() + nodes = conn.execute('SELECT id, ip FROM nodes').fetchall() + conn.close() - if proc.returncode == 0: - # Node ist online, führe SSH Info-Check durch - await check_and_update_node(n['id']) - else: - # Node ist offline - conn = get_db() - conn.execute("UPDATE nodes SET status='Offline' WHERE id=?", (n['id'],)) - conn.commit() - conn.close() + for n in nodes: + # Schneller Ping + proc = await asyncio.create_subprocess_exec( + "ping", "-c", "1", "-W", "1", n['ip'], + stdout=asyncio.subprocess.DEVNULL, + stderr=asyncio.subprocess.DEVNULL + ) + await proc.wait() + + if proc.returncode == 0: + await check_and_update_node(n['id']) + else: + conn = get_db() + conn.execute("UPDATE nodes SET status='Offline' WHERE id=?", (n['id'],)) + conn.commit() + conn.close() + print(f"⚠️ Auto-Refresh: Node {n['ip']} ist per Ping nicht erreichbar.") + + except Exception as e: + print(f"🚨 Schwerer Fehler im Auto-Refresh Loop: {e}") + + # Erst am Ende der Runde warten + await asyncio.sleep(60) # Hilfsfunktion für den Info-Check via SSH async def check_and_update_node(node_id: int): @@ -211,10 +225,8 @@ async def check_and_update_node(node_id: int): node = conn.execute('SELECT * FROM nodes WHERE id = ?', (node_id,)).fetchone() if not node: conn.close() - return "Node nicht gefunden" - - # Wir bauen den Befehl kompakt zusammen - # Nutze im Grep nun doppelte Anführungszeichen, um Konflikte zu vermeiden + return + check_cmd = ( 'arch=$(uname -m); ' 'dock=$(command -v docker >/dev/null 2>&1 && echo 1 || echo 0); ' @@ -224,39 +236,33 @@ async def check_and_update_node(node_id: int): 'echo "$arch|$dock|$os|$vnc"' ) - # WICHTIG: Als Liste übergeben, damit kein f-String Quoting nötig ist! - ssh_args = [ - "ssh", - "-o", "StrictHostKeyChecking=no", - "-o", "ConnectTimeout=3", - f"{node['user']}@{node['ip']}", - check_cmd - ] - try: - # Kein shell=True mehr nötig - output = subprocess.check_output(ssh_args, stderr=subprocess.STDOUT).decode().strip() + # Hier nutzen wir jetzt den asynchronen Subprocess-Aufruf von asyncio + proc = await asyncio.create_subprocess_exec( + "ssh", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=3", + f"{node['user']}@{node['ip']}", check_cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await proc.communicate() - # Debugging: Falls doch was schief geht, sehen wir es im Log - if "|" not in output: - raise ValueError(f"Unerwarteter Output: {output}") + if proc.returncode == 0: + output = stdout.decode().strip() + arch, dock, os_name, vnc = output.split('|') + status = "Docker Aktiv" if dock == "1" else "Bereit (Kein Docker)" + + conn.execute(''' + UPDATE nodes SET status=?, arch=?, docker=?, os=?, vnc=? WHERE id=? + ''', (status, arch, int(dock), os_name, int(vnc), node_id)) + conn.commit() + print(f"✅ Auto-Refresh: Node {node['ip']} ist online ({status})") + else: + raise Exception(stderr.decode()) - arch, dock, os_name, vnc = output.split('|') - status = "Docker Aktiv" if dock == "1" else "Bereit (Kein Docker)" - - conn.execute(''' - UPDATE nodes - SET status=?, arch=?, docker=?, os=?, vnc=? - WHERE id=? - ''', (status, arch, int(dock), os_name, int(vnc), node_id)) - conn.commit() - return status - except Exception as e: - print(f"Fehler bei Node {node_id} ({node['ip']}): {e}") + print(f"❌ Auto-Refresh Fehler bei {node['ip']}: {e}") conn.execute("UPDATE nodes SET status='Offline/Fehler' WHERE id=?", (node_id,)) conn.commit() - return "Offline/Fehler" finally: conn.close()