main.py aktualisiert

This commit is contained in:
2026-03-06 10:33:59 +00:00
parent 89d41e0343
commit 099609fa29

110
main.py
View File

@@ -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()
try:
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()
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:
# 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()
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"
return
# Wir bauen den Befehl kompakt zusammen
# Nutze im Grep nun doppelte Anführungszeichen, um Konflikte zu vermeiden
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)"
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
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())
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()