SPICE-Anzeige und USB-Weiterleitung fuer Wiederherstellungen
Der Anlass: ein Software-Schutzmodul am USB-Port. Normalerweise haengt so ein Dongle an einem USB-Server im Netz - eine abgeschottete Wiederherstellung hat aber keins. Ueber SPICE kommt das Geraet vom Rechner des Bedieners, nicht ueber das Gastnetz. Die Maschine bleibt also ohne Netzwerk und hat trotzdem ihren Dongle. --spice SPICE-Anzeige (vga: qxl), zusaetzlich zu noVNC --usb <n> so viele USB-Weiterleitungen --iso <volid> Abbild als CD einlegen spice <vmid> Verbindungsdatei fuer remote-viewer (.vv) Zwei Dinge zeigte erst der Test, beide haetten die Sache still unbrauchbar gemacht: vga: qxl zerstoert den geladenen Arbeitsspeicher. qxl hat 64 MB Grafikspeicher, die Vorgabe 16 - beim Laden kommt "Size mismatch: vga.vram", und die Maschine bleibt angehalten stehen. Wieder mit TASK OK. Wird jetzt abgelehnt, mit den drei Auswegen in der Meldung. Der dauerhafte ist, am Original 'vga: qxl' zu setzen - dann tragen alle kuenftigen Snapshots es mit und beides geht gleichzeitig. USB ohne SPICE ist wirkungslos. QEMU legt die usbredir-Geraete zwar an, aber ohne SPICE-Server gibt es keinen Kanal dafuer - spiceproxy sagt schlicht "no spice port". --usb schaltet die Anzeige deshalb mit ein. Ausserdem korrigiert: in der .vv-Datei darf das Zertifikat nicht in echte Zeilenumbrueche uebersetzt werden. virt-viewer erwartet die Zeichenfolge \n als zwei Zeichen in einer einzigen Zeile; sonst steht nur die erste hinter "ca=". tools/get-guest-tools.sh holt virtio-win auf einen ISO-Storage. Fuer den Dongle wird davon nichts gebraucht - die Tools sind nur fuer Zwischenablage, Aufloesung und Mauszeiger. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a1076c6641
commit
e88a80cb25
@@ -444,6 +444,9 @@ class Spec:
|
||||
net: str = "" # leer = Vorgabe des Modus; none|down|on
|
||||
resume: object = None # None = RAM-Zustand nehmen, wenn vorhanden
|
||||
transfers: list = field(default_factory=list) # Namen vorhandener Laufwerke
|
||||
spice: bool = False # SPICE-Anzeige (vga: qxl)
|
||||
usb: int = 0 # so viele USB-Weiterleitungen fuer SPICE
|
||||
iso: str = "" # Abbild als CD einlegen (volid)
|
||||
memory: int = 0 # 0 = wie im Snapshot
|
||||
cores: int = 0
|
||||
name: str = ""
|
||||
@@ -470,6 +473,9 @@ class Plan:
|
||||
vmstate_bytes: int = 0
|
||||
resume: bool = False
|
||||
transfers: list = field(default_factory=list) # [transfer.Volume]
|
||||
spice: bool = False
|
||||
usb: int = 0
|
||||
iso: str = ""
|
||||
warnings: list = field(default_factory=list)
|
||||
# Was nicht nur unschoen, sondern gefaehrlich ist. Hierfuer genuegt ein
|
||||
# beilaeufiges "ja" nicht - siehe cmd_create() und die Oberflaeche.
|
||||
@@ -740,6 +746,54 @@ def plan(proxmox, guest, snapname, spec):
|
||||
% (name, volume.state_text))
|
||||
result.transfers.append(volume)
|
||||
|
||||
# -- SPICE, USB-Weiterleitung, CD --------------------------------------
|
||||
result.usb = max(0, int(spec.usb or 0))
|
||||
result.spice = bool(spec.spice)
|
||||
result.iso = spec.iso or ""
|
||||
|
||||
if result.usb > 14:
|
||||
raise RecoveryError("Hoechstens 14 USB-Weiterleitungen.")
|
||||
|
||||
# USB-Weiterleitung laeuft ueber den SPICE-Kanal. Ohne SPICE legt QEMU die
|
||||
# Geraete zwar an, aber es gibt keine Verbindung, die sie transportiert -
|
||||
# "no spice port". Also gehoert beides zusammen.
|
||||
if result.usb and not result.spice:
|
||||
result.spice = True
|
||||
result.notes.append(
|
||||
"SPICE-Anzeige wird mit eingeschaltet: die USB-Weiterleitung laeuft "
|
||||
"ueber den SPICE-Kanal, ohne den waeren die Anschluesse wirkungslos.")
|
||||
|
||||
original_vga = str(config.get("vga") or "")
|
||||
if result.spice and result.resume and not original_vga.startswith("qxl"):
|
||||
raise RecoveryError(
|
||||
"SPICE und geladener Arbeitsspeicher gehen bei dieser Maschine "
|
||||
"nicht zusammen.\n"
|
||||
"SPICE verlangt 'vga: qxl' (64 MB Grafikspeicher), im Snapshot "
|
||||
"steckt die Vorgabe mit 16 MB. Der gespeicherte Zustand passt dann "
|
||||
"nicht mehr und die Maschine bleibt beim Laden haengen "
|
||||
"('Size mismatch: vga.vram').\n"
|
||||
"\n"
|
||||
"Moeglichkeiten:\n"
|
||||
" --no-resume kalt starten, dafuer mit SPICE und USB\n"
|
||||
" ohne --spice warmer RAM-Zustand, dafuer nur noVNC\n"
|
||||
"\n"
|
||||
"Dauerhaft loesen laesst sich das nur am Original: steht dort "
|
||||
"'vga: qxl', tragen alle kuenftigen Snapshots das mit, und beides "
|
||||
"geht gleichzeitig.")
|
||||
|
||||
if result.spice:
|
||||
result.notes.append(
|
||||
"Zugang auf zwei Wegen: noVNC im Browser und SPICE ueber "
|
||||
"'pvesnap-recovery spice %d' (remote-viewer)." % result.newid)
|
||||
if result.usb:
|
||||
result.notes.append(
|
||||
"Im remote-viewer unter 'USB-Geraeteauswahl' das Geraet anhaken - "
|
||||
"es kommt vom eigenen Rechner, nicht ueber das Netz des Gastes. "
|
||||
"Guest-Tools braucht es dafuer nicht.")
|
||||
if result.iso:
|
||||
result.notes.append("Eingelegt wird %s - im Gast als CD-Laufwerk."
|
||||
% result.iso)
|
||||
|
||||
# -- Hinweise ----------------------------------------------------------
|
||||
if result.dropped and not spec.keep_binds:
|
||||
result.notes.append("Nicht uebernommen werden Einbindungen von Host-"
|
||||
@@ -874,6 +928,20 @@ def create(proxmox, plan_, progress=None):
|
||||
attached.append({"name": volume.name, "key": slot, "drive": value,
|
||||
"kind": "disk", "pending": bool(plan_.resume)})
|
||||
|
||||
# -- SPICE, USB-Weiterleitung, CD ----------------------------------
|
||||
if plan_.spice:
|
||||
step("Schalte SPICE-Anzeige ein (vga: qxl)")
|
||||
new_config["vga"] = "qxl"
|
||||
for _ in range(plan_.usb):
|
||||
slot = _free_usb_slot(new_config)
|
||||
new_config[slot] = "spice"
|
||||
if plan_.usb:
|
||||
step("%d USB-Weiterleitung(en) fuer SPICE eingerichtet" % plan_.usb)
|
||||
if plan_.iso:
|
||||
slot = _free_cdrom_slot(new_config)
|
||||
new_config[slot] = "%s,media=cdrom" % plan_.iso
|
||||
step("Lege %s als CD ein (%s)" % (plan_.iso, slot))
|
||||
|
||||
# -- restliche Anpassungen -----------------------------------------
|
||||
if spec.memory:
|
||||
new_config["memory"] = spec.memory
|
||||
@@ -1101,6 +1169,41 @@ def insert_transfer(proxmox, instance, name, progress=None):
|
||||
return True
|
||||
|
||||
|
||||
# Die Reihenfolge ist die einer .vv-Datei fuer remote-viewer; "ca" muss ganz
|
||||
# zum Schluss, weil das Zertifikat mehrzeilig ist.
|
||||
_VV_KEYS = ("type", "host", "port", "tls-port", "password", "proxy",
|
||||
"host-subject", "title", "toggle-fullscreen", "release-cursor",
|
||||
"secure-attention", "delete-this-file", "ca")
|
||||
|
||||
|
||||
def spice_file(proxmox, instance):
|
||||
"""Verbindungsbeschreibung fuer remote-viewer (.vv) als Text.
|
||||
|
||||
Proxmox liefert die Angaben als JSON; daraus wird hier die Datei gebaut,
|
||||
die virt-viewer erwartet. Sie enthaelt ein Einmal-Kennwort und laeuft nach
|
||||
kurzer Zeit ab - also frisch erzeugen, wenn sie nicht mehr zieht.
|
||||
"""
|
||||
data = proxmox._json(["create", "/nodes/%s/%s/%d/spiceproxy"
|
||||
% (instance.node, instance.type, instance.vmid)])
|
||||
if not isinstance(data, dict) or not data.get("host"):
|
||||
raise RecoveryError(
|
||||
"%s liefert keine SPICE-Verbindung. Laeuft die Maschine, und ist "
|
||||
"die SPICE-Anzeige eingeschaltet (vga: qxl)?" % instance.label)
|
||||
|
||||
lines = ["[virt-viewer]"]
|
||||
for key in _VV_KEYS:
|
||||
if key in data and data[key] not in (None, ""):
|
||||
# Bewusst ohne Umwandlung: das Zertifikat enthaelt die Zeichenfolge
|
||||
# \n als zwei Zeichen, und genau so erwartet virt-viewer sie. Wuerde
|
||||
# man daraus echte Zeilenumbrueche machen, stuende nur die erste
|
||||
# Zeile hinter "ca=" und der Rest waere kaputt.
|
||||
lines.append("%s=%s" % (key, data[key]))
|
||||
for key in sorted(data):
|
||||
if key not in _VV_KEYS and data[key] not in (None, ""):
|
||||
lines.append("%s=%s" % (key, data[key]))
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def _default_name(guest, plan_):
|
||||
base = re.sub(r"[^A-Za-z0-9-]", "-", guest.name or "vm%d" % guest.vmid)[:40]
|
||||
return ("%s-wdh" % base).strip("-")
|
||||
@@ -1132,6 +1235,27 @@ def _free_disk_slot(config):
|
||||
raise RecoveryError("Kein freier Platz fuer ein Austauschlaufwerk.")
|
||||
|
||||
|
||||
def _free_usb_slot(config):
|
||||
for index in range(0, 14):
|
||||
key = "usb%d" % index
|
||||
if key not in config:
|
||||
return key
|
||||
raise RecoveryError("Alle 14 USB-Anschluesse sind belegt.")
|
||||
|
||||
|
||||
def _free_cdrom_slot(config):
|
||||
"""Ein CD-Laufwerk - moeglichst das leere, das schon da ist."""
|
||||
for key in sorted(config):
|
||||
if QEMU_DISK_KEY.match(key) and "media=cdrom" in str(config[key]) \
|
||||
and str(config[key]).split(",")[0] in ("none", "cdrom"):
|
||||
return key
|
||||
for index in range(0, 4):
|
||||
key = "ide%d" % index
|
||||
if key not in config:
|
||||
return key
|
||||
raise RecoveryError("Kein Platz fuer ein CD-Laufwerk frei.")
|
||||
|
||||
|
||||
def _free_mp_slot(config):
|
||||
for index in range(0, 256):
|
||||
if "mp%d" % index not in config:
|
||||
|
||||
+64
-1
@@ -27,7 +27,8 @@ 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 (RecoveryError, Spec, create,
|
||||
eject_transfer, insert_transfer, transfer_state,
|
||||
eject_transfer, insert_transfer, spice_file,
|
||||
transfer_state,
|
||||
destroy, find_orphans, flatten, flatten_cost, flatten_hint,
|
||||
human_bytes, linked_volumes, list_instances, plan,
|
||||
remove_orphans, start)
|
||||
@@ -165,6 +166,13 @@ def _fields(guest):
|
||||
if guest.type == "qemu":
|
||||
rows.append(("resume", "Arbeitsspeicher", "choice", RESUME_CHOICES))
|
||||
rows.append(("transfers", "Transfer-Laufwerke", "transfers", ()))
|
||||
if guest.type == "qemu":
|
||||
rows.append(("spice", "SPICE-Anzeige", "choice",
|
||||
((False, "nein - nur noVNC im Browser"),
|
||||
(True, "ja - zusaetzlich remote-viewer"))))
|
||||
rows.append(("usb", "USB-Weiterleitung", "choice",
|
||||
((0, "keine"), (1, "1 Anschluss"), (2, "2 Anschluesse"),
|
||||
(4, "4 Anschluesse"))))
|
||||
rows += [
|
||||
("newid", "Neue VMID", "text", ()),
|
||||
("node", "Node", "text", ()),
|
||||
@@ -214,6 +222,10 @@ def _options(win, guest, spec):
|
||||
"sie standen - ohne Crash-Recovery.",
|
||||
"transfers": "Vorbereitete Austauschmedien. Anlegen und befuellen "
|
||||
"in der Uebersicht mit v .",
|
||||
"spice": "Zweiter Zugang ueber remote-viewer. Achtung: vertraegt "
|
||||
"sich nicht mit geladenem Arbeitsspeicher.",
|
||||
"usb": "Ein USB-Geraet vom eigenen Rechner in den Gast reichen - "
|
||||
"etwa einen Dongle. Laeuft ueber SPICE, nicht ueber das Netz.",
|
||||
"newid": "VMID der neuen Maschine.",
|
||||
"node": "Auf welchem Node sie laufen soll.",
|
||||
"start": "Sofort hochfahren.",
|
||||
@@ -321,6 +333,14 @@ def summary_lines(plan_):
|
||||
% (human_bytes(plan_.vmstate_bytes) or "?")
|
||||
if plan_.resume else "vorhanden, wird aber nicht geladen"),
|
||||
curses.color_pair(C_OK) if plan_.resume else 0))
|
||||
if plan_.spice:
|
||||
lines.append(("Anzeige: noVNC und SPICE (vga: qxl)",
|
||||
curses.color_pair(C_OK)))
|
||||
if plan_.usb:
|
||||
lines.append(("USB: %d Weiterleitung(en) ueber SPICE" % plan_.usb,
|
||||
curses.color_pair(C_OK)))
|
||||
if plan_.iso:
|
||||
lines.append(("CD: %s" % plan_.iso, 0))
|
||||
for volume in plan_.transfers:
|
||||
lines.append(("Transfer: %-14s %8s im Gast als %s"
|
||||
% (volume.name, human_bytes(volume.size), volume.label),
|
||||
@@ -449,6 +469,9 @@ def _details(stdscr, proxmox, instance):
|
||||
if instance.type == "lxc":
|
||||
lines.append((" oder auf dem Host: pct enter %d" % instance.vmid,
|
||||
curses.color_pair(C_MARK)))
|
||||
else:
|
||||
lines.append((" SPICE (remote-viewer): pvesnap-recovery spice %d"
|
||||
% instance.vmid, curses.color_pair(C_MARK)))
|
||||
|
||||
if instance.resumed:
|
||||
lines.append(("", 0))
|
||||
@@ -713,6 +736,9 @@ def _spec_from_args(args, mode):
|
||||
spec.net = args.net or ""
|
||||
spec.resume = args.resume
|
||||
spec.transfers = list(args.transfer or [])
|
||||
spec.spice = bool(getattr(args, "spice", False))
|
||||
spec.usb = int(getattr(args, "usb", 0) or 0)
|
||||
spec.iso = getattr(args, "iso", "") or ""
|
||||
spec.memory = args.memory or 0
|
||||
spec.cores = args.cores or 0
|
||||
spec.name = args.name or ""
|
||||
@@ -877,6 +903,28 @@ def cmd_cleanup(proxmox, args):
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
def cmd_spice(proxmox, args):
|
||||
instance = _find_instance(proxmox, args.vmid)
|
||||
text = spice_file(proxmox, instance)
|
||||
if args.output:
|
||||
with open(args.output, "w", encoding="utf-8") as handle:
|
||||
handle.write(text)
|
||||
os.chmod(args.output, 0o600)
|
||||
print(args.output)
|
||||
print("\n Auf dem eigenen Rechner oeffnen:", file=sys.stderr)
|
||||
print(" scp root@%s:%s . && remote-viewer %s"
|
||||
% (instance.node, args.output, os.path.basename(args.output)),
|
||||
file=sys.stderr)
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
print("\n Umleiten und mit remote-viewer oeffnen:", file=sys.stderr)
|
||||
print(" pvesnap-recovery spice %d -o vm.vv" % instance.vmid,
|
||||
file=sys.stderr)
|
||||
print(" Das Kennwort darin ist ein Einmal-Kennwort und laeuft bald ab.",
|
||||
file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_console(proxmox, args):
|
||||
instance = _find_instance(proxmox, args.vmid)
|
||||
print(instance.console_url())
|
||||
@@ -911,6 +959,14 @@ def _add_create_options(parser):
|
||||
help="Arbeitsspeicher des Snapshots laden")
|
||||
parser.add_argument("--no-resume", dest="resume", action="store_false",
|
||||
help="kalt starten, auch wenn der Snapshot RAM enthaelt")
|
||||
parser.add_argument("--spice", action="store_true",
|
||||
help="SPICE-Anzeige einschalten (vga: qxl) - vertraegt "
|
||||
"sich nicht mit geladenem Arbeitsspeicher")
|
||||
parser.add_argument("--usb", type=int, default=0, metavar="ANZAHL",
|
||||
help="so viele USB-Weiterleitungen ueber SPICE, z.B. "
|
||||
"fuer einen Dongle (geht auch mit RAM-Zustand)")
|
||||
parser.add_argument("--iso", metavar="VOLID",
|
||||
help="Abbild als CD einlegen, z.B. local:iso/virtio-win.iso")
|
||||
parser.add_argument("--transfer", action="append", metavar="NAME", default=[],
|
||||
help="vorbereitetes Transfer-Laufwerk anhaengen "
|
||||
"(mehrfach moeglich)")
|
||||
@@ -978,6 +1034,12 @@ def build_parser():
|
||||
sub = subs.add_parser(name, help=helptext)
|
||||
sub.add_argument("vmid", type=int)
|
||||
|
||||
spice = subs.add_parser("spice",
|
||||
help="SPICE-Verbindungsdatei fuer remote-viewer")
|
||||
spice.add_argument("vmid", type=int)
|
||||
spice.add_argument("-o", "--output", metavar="DATEI",
|
||||
help="hineinschreiben statt auf die Ausgabe")
|
||||
|
||||
flatten_ = subs.add_parser(
|
||||
"flatten", help="vom Quell-Snapshot loesen - fuer den Dauerbetrieb")
|
||||
flatten_.add_argument("vmid", type=int)
|
||||
@@ -1020,6 +1082,7 @@ def main(argv=None):
|
||||
"flatten": lambda: cmd_flatten(proxmox, args),
|
||||
"cleanup": lambda: cmd_cleanup(proxmox, args),
|
||||
"console": lambda: cmd_console(proxmox, args),
|
||||
"spice": lambda: cmd_spice(proxmox, args),
|
||||
"start": lambda: cmd_start(proxmox, args),
|
||||
"stop": lambda: cmd_stop(proxmox, args),
|
||||
}
|
||||
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
# ---------------------------------------------------------------------
|
||||
# Guest-Tools fuer wiederhergestellte Maschinen holen
|
||||
#
|
||||
# Die USB-Weiterleitung ueber SPICE braucht im Gast NICHTS - ein
|
||||
# weitergereichter Dongle taucht dort als gewoehnliches USB-Geraet auf.
|
||||
# Die Tools sind nur fuer den Komfort: Zwischenablage, automatische
|
||||
# Aufloesung, sauberer Mauszeiger.
|
||||
#
|
||||
# Aufruf: ./get-guest-tools.sh [--storage <name>] [--list]
|
||||
#
|
||||
# --storage <name> wohin (Vorgabe: erster Storage mit iso-Inhalt)
|
||||
# --list nur zeigen, was da ist
|
||||
# -h, --help diese Hilfe
|
||||
#
|
||||
# Danach beim Anlegen einlegen:
|
||||
# pvesnap-recovery live 802 --spice --usb 2 --iso <storage>:iso/<datei>
|
||||
# ---------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
STORAGE=""
|
||||
LIST=0
|
||||
|
||||
# virtio-win enthaelt fuer Windows alles auf einmal: den qxl-Grafiktreiber,
|
||||
# den SPICE-Agenten und die virtio-Treiber. Fuer Linux gibt es nichts zu
|
||||
# holen - dort genuegt das Paket der Distribution.
|
||||
WINDOWS_URL="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"
|
||||
WINDOWS_NAME="virtio-win.iso"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--storage) STORAGE="${2:-}"; shift ;;
|
||||
--storage=*) STORAGE="${1#*=}" ;;
|
||||
--list) LIST=1 ;;
|
||||
-h|--help) sed -n '2,19p' "$0" | sed 's/^#[[:space:]]\{0,1\}//'; exit 0 ;;
|
||||
*) echo "Unbekannte Option: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
info() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m==>\033[0m %s\n' "$*" >&2; }
|
||||
fail() { printf '\033[1;31m==>\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
command -v pvesm >/dev/null 2>&1 || fail "pvesm nicht gefunden - das gehoert auf einen Proxmox-Host."
|
||||
|
||||
# Storage bestimmen: der erste, der iso-Inhalt aufnimmt
|
||||
if [ -z "$STORAGE" ]; then
|
||||
STORAGE="$(pvesm status --content iso 2>/dev/null | awk 'NR>1 && $3=="active" {print $1; exit}')"
|
||||
[ -n "$STORAGE" ] || fail "Kein Storage mit iso-Inhalt gefunden.
|
||||
In der Proxmox-Oberflaeche unter Datacenter -> Storage bei einem Storage
|
||||
den Inhalt 'ISO image' zulassen, oder --storage angeben."
|
||||
fi
|
||||
|
||||
DIR="$(pvesm path "${STORAGE}:iso/x" 2>/dev/null | xargs dirname 2>/dev/null || true)"
|
||||
[ -n "$DIR" ] || fail "Ablageort von '${STORAGE}' nicht ermittelbar."
|
||||
|
||||
if [ "$LIST" -eq 1 ]; then
|
||||
info "Vorhandene Abbilder auf '${STORAGE}' (${DIR}):"
|
||||
pvesm list "$STORAGE" --content iso 2>/dev/null | tail -n +2 | sed 's/^/ /' \
|
||||
|| echo " (keine)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
info "Ablage: ${DIR}"
|
||||
mkdir -p "$DIR"
|
||||
|
||||
# --- Windows ---------------------------------------------------------
|
||||
TARGET="${DIR}/${WINDOWS_NAME}"
|
||||
if [ -f "$TARGET" ]; then
|
||||
info "Schon da: ${STORAGE}:iso/${WINDOWS_NAME} ($(du -h "$TARGET" | cut -f1))"
|
||||
else
|
||||
info "Hole virtio-win (Windows: qxl-Treiber, SPICE-Agent, virtio-Treiber)"
|
||||
command -v curl >/dev/null 2>&1 || fail "curl wird benoetigt."
|
||||
if curl -fL --progress-bar -o "${TARGET}.teil" "$WINDOWS_URL"; then
|
||||
mv "${TARGET}.teil" "$TARGET"
|
||||
info "Fertig: ${STORAGE}:iso/${WINDOWS_NAME} ($(du -h "$TARGET" | cut -f1))"
|
||||
else
|
||||
rm -f "${TARGET}.teil"
|
||||
fail "Herunterladen fehlgeschlagen. Hat der Host Internetzugang?
|
||||
Sonst von Hand holen und nach ${DIR} legen:
|
||||
${WINDOWS_URL}"
|
||||
fi
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Beim Anlegen einlegen:
|
||||
|
||||
pvesnap-recovery live <VMID> --spice --usb 2 --iso ${STORAGE}:iso/${WINDOWS_NAME}
|
||||
|
||||
Im Gast danach:
|
||||
|
||||
Windows Von der CD 'virtio-win-guest-tools.exe' ausfuehren.
|
||||
Linux Nichts von der CD - das Paket der Distribution nehmen:
|
||||
apt install spice-vdagent (Debian/Ubuntu)
|
||||
dnf install spice-vdagent (Fedora/RHEL)
|
||||
|
||||
Fuer einen weitergereichten USB-Dongle braucht es davon nichts. Der taucht im
|
||||
Gast als gewoehnliches USB-Geraet auf, sobald du ihn im remote-viewer unter
|
||||
"USB-Geraeteauswahl" anhakst.
|
||||
EOF
|
||||
Reference in New Issue
Block a user