main.py aktualisiert
This commit is contained in:
110
main.py
110
main.py
@@ -15,6 +15,7 @@ from fastapi import FastAPI, WebSocket, BackgroundTasks, Request, Form, WebSocke
|
|||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
from dotenv import load_dotenv, set_key
|
from dotenv import load_dotenv, set_key
|
||||||
|
|
||||||
# Lade Umgebungsvariablen aus der .env Datei
|
# 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.")
|
await manager.broadcast(f"✅ Node {ip} verbunden und analysiert.")
|
||||||
|
|
||||||
# --- AUTO-REFRESH (Alle 60 Sekunden) ---
|
# --- AUTO-REFRESH (Alle 60 Sekunden) ---
|
||||||
@app.on_event("startup")
|
@asynccontextmanager
|
||||||
async def start_auto_refresh():
|
async def lifespan(app: FastAPI):
|
||||||
asyncio.create_task(auto_refresh_loop())
|
# 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():
|
async def auto_refresh_loop():
|
||||||
|
print("🚀 Auto-Refresh Task gestartet...")
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(60) # Alle 60 Sekunden
|
try:
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
nodes = conn.execute('SELECT id, ip FROM nodes').fetchall()
|
nodes = conn.execute('SELECT id, ip FROM nodes').fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
for n in nodes:
|
for n in nodes:
|
||||||
# 1. Schneller Ping-Check, um lange SSH-Timeouts bei Offline-Nodes zu vermeiden
|
# Schneller Ping
|
||||||
proc = await asyncio.create_subprocess_exec(
|
proc = await asyncio.create_subprocess_exec(
|
||||||
"ping", "-c", "1", "-W", "1", n['ip'],
|
"ping", "-c", "1", "-W", "1", n['ip'],
|
||||||
stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL
|
stdout=asyncio.subprocess.DEVNULL,
|
||||||
)
|
stderr=asyncio.subprocess.DEVNULL
|
||||||
await proc.wait()
|
)
|
||||||
|
await proc.wait()
|
||||||
|
|
||||||
if proc.returncode == 0:
|
if proc.returncode == 0:
|
||||||
# Node ist online, führe SSH Info-Check durch
|
await check_and_update_node(n['id'])
|
||||||
await check_and_update_node(n['id'])
|
else:
|
||||||
else:
|
conn = get_db()
|
||||||
# Node ist offline
|
conn.execute("UPDATE nodes SET status='Offline' WHERE id=?", (n['id'],))
|
||||||
conn = get_db()
|
conn.commit()
|
||||||
conn.execute("UPDATE nodes SET status='Offline' WHERE id=?", (n['id'],))
|
conn.close()
|
||||||
conn.commit()
|
print(f"⚠️ Auto-Refresh: Node {n['ip']} ist per Ping nicht erreichbar.")
|
||||||
conn.close()
|
|
||||||
|
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
|
# Hilfsfunktion für den Info-Check via SSH
|
||||||
async def check_and_update_node(node_id: int):
|
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()
|
node = conn.execute('SELECT * FROM nodes WHERE id = ?', (node_id,)).fetchone()
|
||||||
if not node:
|
if not node:
|
||||||
conn.close()
|
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 = (
|
check_cmd = (
|
||||||
'arch=$(uname -m); '
|
'arch=$(uname -m); '
|
||||||
'dock=$(command -v docker >/dev/null 2>&1 && echo 1 || echo 0); '
|
'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"'
|
'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:
|
try:
|
||||||
# Kein shell=True mehr nötig
|
# Hier nutzen wir jetzt den asynchronen Subprocess-Aufruf von asyncio
|
||||||
output = subprocess.check_output(ssh_args, stderr=subprocess.STDOUT).decode().strip()
|
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 proc.returncode == 0:
|
||||||
if "|" not in output:
|
output = stdout.decode().strip()
|
||||||
raise ValueError(f"Unerwarteter Output: {output}")
|
arch, dock, os_name, vnc = output.split('|')
|
||||||
|
status = "Docker Aktiv" if dock == "1" else "Bereit (Kein Docker)"
|
||||||
|
|
||||||
arch, dock, os_name, vnc = output.split('|')
|
conn.execute('''
|
||||||
status = "Docker Aktiv" if dock == "1" else "Bereit (Kein Docker)"
|
UPDATE nodes SET status=?, arch=?, docker=?, os=?, vnc=? WHERE id=?
|
||||||
|
''', (status, arch, int(dock), os_name, int(vnc), node_id))
|
||||||
conn.execute('''
|
conn.commit()
|
||||||
UPDATE nodes
|
print(f"✅ Auto-Refresh: Node {node['ip']} ist online ({status})")
|
||||||
SET status=?, arch=?, docker=?, os=?, vnc=?
|
else:
|
||||||
WHERE id=?
|
raise Exception(stderr.decode())
|
||||||
''', (status, arch, int(dock), os_name, int(vnc), node_id))
|
|
||||||
conn.commit()
|
|
||||||
return status
|
|
||||||
|
|
||||||
except Exception as e:
|
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.execute("UPDATE nodes SET status='Offline/Fehler' WHERE id=?", (node_id,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return "Offline/Fehler"
|
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user