Transfer-Laufwerke im laufenden Betrieb wechseln

Auswerfen und wieder einklinken, ohne die Maschine anzufassen - damit laesst
sich mehrfach nachladen und abholen, statt nur einmal am Ende.

    eject_transfer()    zieht die Platte ab, danach gehoert sie dem Host
    insert_transfer()   gibt sie zurueck in denselben Steckplatz
    transfer_state()    was gerade wirklich steckt

In der Detailansicht auf Taste e; bei mehreren Laufwerken mit Auswahl. Vor dem
Auswerfen wird nachgefragt, mit dem Hinweis, im Gast vorher auszuhaengen -
Proxmox meldet das Geraet zwar ab, aber ein Dateisystem, das noch beschrieben
wird, nimmt das uebel. Schlaegt es fehl, weil der Gast es festhaelt, steht das
auch so in der Meldung.

Beim Container gibt es nichts zu wechseln und das wird auch so gesagt: dort
ist das Verzeichnis durchgereicht, Host und Gast sehen dieselben Dateien
ohnehin gleichzeitig.

Dabei ein Fehler aufgefallen, den erst der Test zeigte: bei einer Maschine mit
geladenem Arbeitsspeicher steckte das Transfer-Laufwerk in der kalten
Konfiguration - der Gast haette es nie bemerkt. Dieselbe Falle wie beim
Austauschlaufwerk, dort schon behoben, hier vergessen. Beide gehen jetzt durch
dieselbe Nachsteck-Logik.

Am laufenden System durchgespielt, mit RAM-Zustand:

    Start        "Stecke Transfer-Laufwerk 'hotswap' als scsi2 an"
    auswerfen    eingesteckt=False, Laufwerk wieder frei
    befuellen    runde2.txt vom Host, VM lief weiter
    einklinken   scsi2: /dev/loop0,backup=0,size=1G
    Ende         beide Dateien da, VM durchgehend running

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-08-03 09:24:47 +02:00
co-authored by Claude Opus 5
parent 2b895e6f4f
commit 0a92ec0984
2 changed files with 193 additions and 14 deletions
+51 -1
View File
@@ -27,6 +27,7 @@ from .curses_util import (C_DIM, C_FOOTER, C_HEADER, C_MARK, C_OK, C_SEL, C_WARN
keybar, message, prompt, put, read_key)
from .proxmox import Proxmox, ProxmoxError, pvesh_available
from .recovery import (EXCHANGE_GUEST_PATH, RecoveryError, Spec, create,
eject_transfer, insert_transfer, transfer_state,
destroy, find_orphans, flatten, flatten_cost, flatten_hint,
human_bytes,
linked_volumes, list_instances, plan, pull, release,
@@ -476,6 +477,24 @@ def _details(stdscr, proxmox, instance):
"ersten Start lief die Maschine genau weiter.",
curses.color_pair(C_DIM)))
steckplaetze = transfer_state(proxmox, instance)
if steckplaetze:
lines.append(("", 0))
lines.append(("Transfer-Laufwerke:", 0))
for entry, drin in steckplaetze:
if entry.get("kind") == "bind":
zustand = "durchgereicht (Host und Gast gleichzeitig)"
farbe = C_OK
else:
zustand = ("eingesteckt als %s" % entry["key"]) if drin \
else "ausgeworfen - gehoert dem Host"
farbe = C_OK if drin else C_MARK
lines.append((" %-14s %s" % (entry["name"], zustand),
curses.color_pair(farbe)))
if any(e.get("kind") != "bind" for e, _ in steckplaetze):
lines.append((" e = auswerfen / einklinken, im laufenden "
"Betrieb", curses.color_pair(C_DIM)))
try:
linked = linked_volumes(proxmox, instance)
except (RecoveryError, ProxmoxError):
@@ -493,7 +512,7 @@ def _details(stdscr, proxmox, instance):
lines.append(("Datentraeger: eigenstaendig - haengt an keinem Snapshot",
curses.color_pair(C_OK)))
footer = ("s Starten | h Herunterfahren | a Austausch | f Loesen | "
footer = ("s Start | h Stop | e Auswerfen | a Austausch | f Loesen | "
"x Verwerfen | q zurueck")
key = _pages(stdscr, lines, "Wiederherstellung %s" % instance.label, footer)
@@ -507,6 +526,8 @@ def _details(stdscr, proxmox, instance):
lambda: proxmox.shutdown_guest(instance.guest))
elif key in ("a", "A"):
_pull(stdscr, proxmox, instance)
elif key in ("e", "E"):
_swap(stdscr, proxmox, instance, steckplaetze)
elif key in ("f", "F"):
_flatten(stdscr, proxmox, instance, linked)
elif key in ("x", "X"):
@@ -545,6 +566,35 @@ def _pull(stdscr, proxmox, instance):
]), "Austauschlaufwerk")
def _swap(stdscr, proxmox, instance, steckplaetze):
"""Transfer-Laufwerk im laufenden Betrieb abziehen oder wieder einklinken."""
wechselbar = [(e, drin) for e, drin in steckplaetze if e.get("kind") != "bind"]
if not wechselbar:
message(stdscr, "Hier gibt es nichts zu wechseln.", error=True)
return
if len(wechselbar) == 1:
entry, drin = wechselbar[0]
else:
gewaehlt = choose(stdscr, "Welches Laufwerk?",
[((e, d), "%-14s %s" % (e["name"],
"eingesteckt" if d else "ausgeworfen"))
for e, d in wechselbar])
if gewaehlt is None:
return
entry, drin = gewaehlt
name = entry["name"]
if drin:
if not confirm(stdscr, "%r auswerfen? Im Gast vorher aushaengen!" % name):
return
_do(stdscr, "Werfe %r aus ..." % name,
lambda: eject_transfer(proxmox, instance, name))
else:
_do(stdscr, "Klinke %r ein ..." % name,
lambda: insert_transfer(proxmox, instance, name))
def _flatten(stdscr, proxmox, instance, linked):
if not linked:
message(stdscr, "%s haengt an keinem Snapshot mehr." % instance.label)