pi_admin/main.py aktualisiert
This commit is contained in:
@@ -1,14 +1,20 @@
|
|||||||
import json
|
|
||||||
import os
|
import os
|
||||||
from fastapi import FastAPI, Request, WebSocket
|
import subprocess
|
||||||
|
import pty
|
||||||
|
import select
|
||||||
|
import threading
|
||||||
|
import json
|
||||||
|
import paramiko
|
||||||
|
from fastapi import FastAPI, WebSocket, BackgroundTasks, Request
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
import paramiko
|
|
||||||
from python_on_whales import DockerClient
|
from python_on_whales import DockerClient
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
# Pfad zum SSH-Key
|
||||||
|
SSH_KEY = os.path.expanduser("~/.ssh/id_rsa")
|
||||||
# Speicher für Nodes (einfache JSON-Datei)
|
# Speicher für Nodes (einfache JSON-Datei)
|
||||||
NODES_FILE = "nodes.json"
|
NODES_FILE = "nodes.json"
|
||||||
|
|
||||||
@@ -112,6 +118,47 @@ async def chat_endpoint(websocket: WebSocket):
|
|||||||
else:
|
else:
|
||||||
await websocket.send_text("🤖 Auf welchem Pi soll ich Ollama installieren? (Nenne Name oder IP)")
|
await websocket.send_text("🤖 Auf welchem Pi soll ich Ollama installieren? (Nenne Name oder IP)")
|
||||||
|
|
||||||
|
def ensure_ssh_key():
|
||||||
|
if not os.path.exists(SSH_KEY):
|
||||||
|
subprocess.run(["ssh-keygen", "-t", "rsa", "-N", "", "-f", SSH_KEY])
|
||||||
|
|
||||||
|
async def deploy_key_and_install(ip, user, password, ws: WebSocket):
|
||||||
|
ensure_ssh_key()
|
||||||
|
await ws.send_text(f"📦 Initialisiere Node {ip}...")
|
||||||
|
|
||||||
|
# 1. SSH-Key kopieren (automatisiert mit sshpass)
|
||||||
|
cmd_copy = f"sshpass -p '{password}' ssh-copy-id -o StrictHostKeyChecking=no {user}@{ip}"
|
||||||
|
process = subprocess.Popen(cmd_copy, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||||
|
|
||||||
|
for line in process.stdout:
|
||||||
|
await ws.send_text(f"🔑 SSH-Key: {line.strip()}")
|
||||||
|
|
||||||
|
# 2. Docker & Ollama Installation (Beispiel-Streaming)
|
||||||
|
await ws.send_text(f"🚀 Starte Setup auf {ip}...")
|
||||||
|
cmd_install = f"ssh {user}@{ip} 'curl -sSL https://get.docker.com | sh && curl -fsSL https://ollama.com/install.sh | sh'"
|
||||||
|
|
||||||
|
process = subprocess.Popen(cmd_install, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||||
|
for line in process.stdout:
|
||||||
|
await ws.send_text(f"🛠️ Install: {line.strip()}")
|
||||||
|
|
||||||
|
# --- WEB TERMINAL LOGIK (Vereinfacht) ---
|
||||||
|
@app.websocket("/ws/terminal/{ip}")
|
||||||
|
async def terminal_websocket(websocket: WebSocket, ip: str):
|
||||||
|
await websocket.accept()
|
||||||
|
|
||||||
|
# Öffne eine echte Shell-Sitzung zum Ziel-Node
|
||||||
|
(master_fd, slave_fd) = pty.openpty()
|
||||||
|
p = subprocess.Popen(["ssh", f"pi@{ip}"], stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, text=True)
|
||||||
|
|
||||||
|
async def pty_to_ws():
|
||||||
|
while True:
|
||||||
|
await websocket.receive_text() # Input vom Browser empfangen (vereinfacht)
|
||||||
|
# Hier müsste xterm.js Input an master_fd geschrieben werden
|
||||||
|
|
||||||
|
# Hinweis: Ein volles Terminal braucht bidirektionales Streaming von Bytes.
|
||||||
|
await websocket.send_text(f"Verbunden mit {ip}. Terminal-Session gestartet.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||||
Reference in New Issue
Block a user