diff --git a/aria-brain/agent.py b/aria-brain/agent.py index a6af380..8630b5b 100644 --- a/aria-brain/agent.py +++ b/aria-brain/agent.py @@ -1170,15 +1170,20 @@ META_TOOLS = [ "Traegt eine QEMU-VM in die VM-Liste des AKTUELLEN Projekts ein, " "damit sie in Stefans Desktop-Panel (Cockpit) erscheint und er sie " "starten/stoppen/verbinden kann. Rufe das auf, NACHDEM Du mit aria-vm " - "eine VM gebaut/gebootet hast (z.B. bei einem OS-Bau-Projekt). " - "vnc_display bestimmt den VNC-Port (Port = 5900+display)." + "eine VM gebaut/gebootet hast — mit den Medien, die zum Task passen: " + "disk (Festplatte, z.B. DOS-Spiele), floppy (Diskette, OS-Dev), iso " + "(Installer). Leer lassen = aria-vm erkennt disk.qcow2/floppy.img/" + "cdrom.iso im VM-Ordner selbst. vnc_display → Port 5900+display " + "(mehrere VMs = verschiedene Displays)." ), "parameters": { "type": "object", "properties": { "name": {"type": "string", "description": "VM-Name wie bei aria-vm (a-z0-9_-)."}, - "arch": {"type": "string", "description": "z.B. i386, x86_64, aarch64, mips."}, - "iso": {"type": "string", "description": "optional: Boot-ISO-Pfad auf dem Host."}, + "arch": {"type": "string", "description": "z.B. i386, x86_64, aarch64, mips (Architektur zum Task waehlen)."}, + "disk": {"type": "string", "description": "optional: qcow2-Pfad (Festplatte)."}, + "floppy": {"type": "string", "description": "optional: Disketten-Image-Pfad (-fda)."}, + "iso": {"type": "string", "description": "optional: Boot-ISO-Pfad."}, "vnc_display": {"type": "integer", "description": "VNC-Display (Default 1 → Port 5901)."}, "mem": {"type": "integer", "description": "RAM in MB (Default 1024)."}, }, @@ -2839,6 +2844,8 @@ class Agent: pid, (arguments.get("name") or "").strip(), (arguments.get("arch") or "i386").strip(), (arguments.get("iso") or "").strip(), + (arguments.get("floppy") or "").strip(), + (arguments.get("disk") or "").strip(), int(arguments.get("vnc_display") or 1), int(arguments.get("mem") or 1024), ) diff --git a/aria-brain/main.py b/aria-brain/main.py index e7fa22f..a61d10a 100644 --- a/aria-brain/main.py +++ b/aria-brain/main.py @@ -961,20 +961,30 @@ class VmAddBody(BaseModel): name: str arch: str = "i386" iso: str = "" + floppy: str = "" + disk: str = "" vnc_display: int = 1 mem: int = 1024 create_disk: bool = False size: str = "10G" +def _vm_boot_args(v: dict) -> list: + args = ["boot", v.get("name", "?"), + "--vnc-display", str(v.get("vnc_display", 1)), + "--mem", str(v.get("mem", 1024))] + if v.get("disk"): + args += ["--disk", v["disk"]] + if v.get("floppy"): + args += ["--floppy", v["floppy"]] + if v.get("iso"): + args += ["--iso", v["iso"]] + return args + + def _vm_boot_cmd(v: dict) -> str: """Lesbarer Start-Befehl (aria-vm) als 'Wert' hinter dem VM-Eintrag.""" - parts = ["aria-vm", "boot", v.get("name", "?"), - "--vnc-display", str(v.get("vnc_display", 1)), - "--mem", str(v.get("mem", 1024))] - if v.get("iso"): - parts += ["--iso", v["iso"]] - return " ".join(parts) + return "aria-vm " + " ".join(_vm_boot_args(v)) @app.get("/projects/{project_id}/vms") @@ -992,7 +1002,7 @@ def project_vms_list(project_id: str): def project_vm_add(project_id: str, body: VmAddBody): try: vm = project_vms_mod.add_vm(project_id, body.name, body.arch, body.iso, - body.vnc_display, body.mem) + body.floppy, body.disk, body.vnc_display, body.mem) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) if body.create_disk: @@ -1017,11 +1027,7 @@ def project_vm_boot(project_id: str, name: str): vm = project_vms_mod.get_vm(project_id, name) if not vm: raise HTTPException(status_code=404, detail=f"VM '{name}' nicht gefunden") - args = ["boot", name, "--vnc-display", str(vm.get("vnc_display", 1)), - "--mem", str(vm.get("mem", 1024))] - if vm.get("iso"): - args += ["--iso", vm["iso"]] - rc, out, err = _ssh_aria_vm(*args, timeout=40) + rc, out, err = _ssh_aria_vm(*_vm_boot_args(vm), timeout=40) return {"ok": rc == 0, "name": name, "vnc_port": 5900 + int(vm.get("vnc_display", 1)), "output": (out.strip() or err.strip())[:500]} diff --git a/aria-brain/project_vms.py b/aria-brain/project_vms.py index 2068473..67c8084 100644 --- a/aria-brain/project_vms.py +++ b/aria-brain/project_vms.py @@ -52,7 +52,12 @@ def get_vm(project_id: str, name: str) -> Optional[dict]: def add_vm(project_id: str, name: str, arch: str, iso: str = "", + floppy: str = "", disk: str = "", vnc_display: int = 1, mem: int = 1024) -> dict: + """Registriert/aktualisiert eine VM. Medien (disk/floppy/iso) sind optional — + leer = aria-vm erkennt disk.qcow2/floppy.img/cdrom.iso im VM-Ordner selbst. + ARIA setzt hier, was sie zum Task passend gebaut hat (Festplatte fuer DOS- + Spiele, Diskette fuer OS-Dev, ISO fuer Installer).""" if not NAME_RE.match(name or ""): raise ValueError(f"Ungueltiger VM-Name: {name!r} (nur a-z0-9_-, max 40)") if arch not in VALID_ARCH: @@ -60,14 +65,14 @@ def add_vm(project_id: str, name: str, arch: str, iso: str = "", data = _load() lst = data.setdefault(project_id or "", []) now = int(time.time()) + fields = {"arch": arch, "iso": iso, "floppy": floppy, "disk": disk, + "vnc_display": int(vnc_display), "mem": int(mem), "updated_at": now} for v in lst: if v.get("name") == name: - v.update({"arch": arch, "iso": iso, "vnc_display": int(vnc_display), - "mem": int(mem), "updated_at": now}) + v.update(fields) _save(data) return v - vm = {"name": name, "arch": arch, "iso": iso, "vnc_display": int(vnc_display), - "mem": int(mem), "created_at": now, "updated_at": now} + vm = {"name": name, "created_at": now, **fields} lst.append(vm) _save(data) return vm diff --git a/aria-brain/seed_rules.py b/aria-brain/seed_rules.py index 6c0ab4f..5bd2d73 100644 --- a/aria-brain/seed_rules.py +++ b/aria-brain/seed_rules.py @@ -434,11 +434,25 @@ SEED_RULES: List[dict] = [ " - `aria-vm screenshot ` → PNG (an Stefan per [FILE:] schickbar).\n" " - `aria-vm list` / `aria-vm stop ` / `aria-vm rm `.\n" "\n" - "PFLICHT nach dem Bau/Boot: `vm_register(name, arch, vnc_display, mem, iso?)` " - "im aktuellen Projekt aufrufen. ERST DANN erscheint die VM in Stefans " - "Desktop-Panel (Cockpit), wo er sie Starten/Stoppen/Verbinden kann. Ohne " - "vm_register bleibt seine Liste leer, obwohl die VM laeuft. Der Startbefehl " - "steht dann als Wert hinter dem Eintrag.\n" + "PFLICHT nach dem Bau/Boot: `vm_register(name, arch, disk?/floppy?/iso?, " + "vnc_display, mem)` im aktuellen Projekt aufrufen — mit den Medien, die Du " + "gebaut hast. ERST DANN erscheint die VM in Stefans Desktop-Panel (Cockpit), " + "wo er sie Starten/Stoppen/Verbinden kann. Ohne vm_register bleibt seine " + "Liste leer, obwohl die VM laeuft. Der Startbefehl steht als Wert dahinter.\n" + "\n" + "URTEIL — bau eine VM NUR wenn's Sinn macht, und erkenne aus der SITUATION " + "was gebraucht wird:\n" + " - DOS-/Retro-Spiele, installierte Software → FESTPLATTE (create mit " + "Groesse, dann installieren; disk).\n" + " - Eigenes OS / Bootloader / Bare-Metal-Experiment → DISKETTE (create " + "'none', floppy.img; ggf. eine zweite Diskette einbinden).\n" + " - Fertiges System installieren/testen → ISO (--iso Installer).\n" + " - Architektur zum Task waehlen: 'teste mal was auf ARM' → arch=aarch64 " + "(-M virt, laeuft emuliert = langsam, das ist ok). x86-Zeug → i386/x86_64.\n" + "AENDERUNGS-ZYKLUS: willst Du an einer laufenden VM etwas aendern (Datei " + "tauschen, Diskette neu bauen), dann `aria-vm stop ` → Aenderung → " + "`aria-vm boot ` wieder starten. Stefan kann das auch selbst ueber " + "Start/Stop im Panel.\n" "\n" "Der VNC-Stream laeuft AUTOMATISCH komplett durch den RVS-Server (die Bridge " "tunnelt die RFB-Bytes; der VNC-Port ist nur intern auf dem Host). Firewall-"