pi_admin/main.py aktualisiert
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import json
|
||||
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.staticfiles import StaticFiles
|
||||
import paramiko
|
||||
from python_on_whales import DockerClient
|
||||
|
||||
app = FastAPI()
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
# Pfad zum SSH-Key
|
||||
SSH_KEY = os.path.expanduser("~/.ssh/id_rsa")
|
||||
# Speicher für Nodes (einfache JSON-Datei)
|
||||
NODES_FILE = "nodes.json"
|
||||
|
||||
@@ -112,6 +118,47 @@ async def chat_endpoint(websocket: WebSocket):
|
||||
else:
|
||||
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__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
Reference in New Issue
Block a user