Neustart: auf das Herunterfahren im Gast warten statt es zu erzwingen
ACPI klappt bei Linux, bei Windows haeufig nicht - dort blockiert gern eine
Anwendung den Vorgang oder der Shutdown Event Tracker fragt nach einem Grund.
Deshalb gibt es jetzt die Wahl:
Ich fahre im Gast herunter - pvesnap wartet und startet dann
Proxmox herunterfahren lassen (ACPI) - Windows blockt das oft
Gar nicht - spaeter selbst
Der erste Weg ist der verlaessliche: pvesnap zeigt, was im Gast zu tun ist,
verfolgt den Zustand und startet die Maschine von selbst wieder, sobald sie
aus ist. Abbrechen geht jederzeit, dann laeuft sie einfach weiter und die
Aenderung greift beim naechsten Start.
Dieselbe Falle steckte in der Taste h: shutdown_guest lief mit force=True und
hat den Gast nach 180 Sekunden hart abgeschaltet - ein Stromausfall, still und
ohne Rueckfrage. Die Vorgabe ist jetzt force=False, und bei Widerstand kommt
dieselbe Wahl: warten, hart ausschalten (mit ausdruecklicher Bestaetigung) oder
abbrechen.
Geprueft: der Wartebildschirm erkennt das Herunterfahren und meldet es zurueck,
der Auswahldialog zeigt alle drei Wege.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8787304f0b
commit
fb3be26c33
+110
-13
@@ -19,6 +19,7 @@ import curses
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from . import __version__
|
||||
@@ -549,8 +550,7 @@ def _details(stdscr, proxmox, instance):
|
||||
_do(stdscr, "Starte %s ..." % instance.label,
|
||||
lambda: start(proxmox, instance))
|
||||
elif key in ("h", "H"):
|
||||
_do(stdscr, "Fahre %s herunter ..." % instance.label,
|
||||
lambda: proxmox.shutdown_guest(instance.guest))
|
||||
_herunterfahren(stdscr, proxmox, instance)
|
||||
elif key in ("e", "E"):
|
||||
_swap(stdscr, proxmox, instance, steckplaetze)
|
||||
elif key in ("v", "V"):
|
||||
@@ -564,6 +564,32 @@ def _details(stdscr, proxmox, instance):
|
||||
return
|
||||
|
||||
|
||||
def _herunterfahren(stdscr, proxmox, instance):
|
||||
"""Sauber herunterfahren - und bei Widerstand nicht einfach zuschlagen."""
|
||||
_wait_screen(stdscr, "Fahre %s herunter ..." % instance.label)
|
||||
try:
|
||||
proxmox.shutdown_guest(instance.guest)
|
||||
return
|
||||
except (ProxmoxError, RecoveryError) as exc:
|
||||
grund = str(exc)
|
||||
|
||||
weg = choose(stdscr, "%s faehrt nicht herunter" % instance.label, [
|
||||
("warten", "Im Gast selbst herunterfahren - pvesnap wartet"),
|
||||
("hart", "Hart ausschalten - wie Stecker ziehen"),
|
||||
(None, "Abbrechen, laeuft weiter"),
|
||||
])
|
||||
if weg == "warten":
|
||||
if _warte_bis_aus(stdscr, proxmox, instance):
|
||||
message(stdscr, "%s ist aus." % instance.label)
|
||||
return
|
||||
if weg == "hart":
|
||||
if confirm(stdscr, "Wirklich hart ausschalten? Daten koennen verloren gehen."):
|
||||
_do(stdscr, "Schalte %s aus ..." % instance.label,
|
||||
lambda: proxmox.stop_guest(instance.guest))
|
||||
return
|
||||
message(stdscr, grund, error=True)
|
||||
|
||||
|
||||
def _do(stdscr, text, action):
|
||||
_wait_screen(stdscr, text)
|
||||
try:
|
||||
@@ -575,6 +601,81 @@ def _do(stdscr, text, action):
|
||||
message(stdscr, hint, error=True)
|
||||
|
||||
|
||||
def _warte_bis_aus(stdscr, proxmox, instance, minuten=30):
|
||||
"""Warten, bis der Gast von innen heruntergefahren ist.
|
||||
|
||||
Der verlaesslichere Weg als ACPI: Windows ignoriert den Aus-Knopf gern,
|
||||
wenn eine Anwendung den Herunterfahrvorgang blockiert oder der Shutdown
|
||||
Event Tracker nach einem Grund fragt. Wer im Gast selbst herunterfaehrt,
|
||||
umgeht das - und pvesnap sieht am Zustand, wann es soweit ist.
|
||||
"""
|
||||
curses.halfdelay(20) # get_wch wartet hoechstens 2s
|
||||
begonnen = time.time()
|
||||
try:
|
||||
while time.time() - begonnen < minuten * 60:
|
||||
try:
|
||||
zustand = proxmox.guest_status(instance.guest).get("status") or "?"
|
||||
except ProxmoxError:
|
||||
zustand = "?"
|
||||
if zustand != "running":
|
||||
return True
|
||||
|
||||
height, width = stdscr.getmaxyx()
|
||||
stdscr.erase()
|
||||
fill(stdscr, 0, " Warte auf das Herunterfahren von %s" % instance.label,
|
||||
curses.color_pair(C_HEADER) | curses.A_BOLD)
|
||||
zeilen = [
|
||||
"Bitte jetzt IM GAST herunterfahren.",
|
||||
"",
|
||||
" Windows Start -> Ein/Aus -> Herunterfahren",
|
||||
" Linux poweroff bzw. shutdown -h now",
|
||||
"",
|
||||
"Sobald die Maschine aus ist, startet pvesnap sie von selbst",
|
||||
"wieder - dann mit der neuen Ausstattung.",
|
||||
"",
|
||||
"Zustand: %s seit %d:%02d"
|
||||
% (zustand, int(time.time() - begonnen) // 60,
|
||||
int(time.time() - begonnen) % 60),
|
||||
]
|
||||
for zeile, text in enumerate(zeilen):
|
||||
put(stdscr, zeile + 2, 3, truncate(text, width - 6),
|
||||
curses.A_BOLD if zeile == 0 else 0)
|
||||
fill(stdscr, height - 1, " q oder Esc = Abbrechen (die Maschine "
|
||||
"laeuft dann einfach weiter)", curses.color_pair(C_FOOTER))
|
||||
stdscr.refresh()
|
||||
|
||||
key = read_key(stdscr)
|
||||
if key in ("q", "Q") or is_escape(key):
|
||||
return False
|
||||
finally:
|
||||
curses.cbreak() # halbe Verzoegerung zuruecknehmen
|
||||
return False
|
||||
|
||||
|
||||
def _neu_starten(stdscr, proxmox, instance):
|
||||
"""Neustart, damit vorgemerkte Aenderungen wirksam werden."""
|
||||
weg = choose(stdscr, "Wie soll %s neu starten?" % instance.label, [
|
||||
("warten", "Ich fahre im Gast herunter - pvesnap wartet und startet dann"),
|
||||
("acpi", "Proxmox herunterfahren lassen (ACPI) - Windows blockt das oft"),
|
||||
(None, "Gar nicht - spaeter selbst"),
|
||||
])
|
||||
if weg is None:
|
||||
message(stdscr, "Eingetragen - wirksam beim naechsten Start.")
|
||||
return
|
||||
|
||||
if weg == "acpi":
|
||||
_do(stdscr, "Fahre %s herunter und wieder hoch ..." % instance.label,
|
||||
lambda: proxmox.reboot_guest(instance.guest))
|
||||
return
|
||||
|
||||
if not _warte_bis_aus(stdscr, proxmox, instance):
|
||||
message(stdscr, "Abgebrochen - die Aenderung greift beim naechsten "
|
||||
"Start. Dann hier mit s starten.")
|
||||
return
|
||||
_do(stdscr, "Ist aus - starte %s wieder ..." % instance.label,
|
||||
lambda: start(proxmox, instance))
|
||||
|
||||
|
||||
def _display(stdscr, proxmox, instance):
|
||||
"""SPICE-Anzeige und USB-Weiterleitung nachtraeglich einstellen."""
|
||||
if instance.type != "qemu":
|
||||
@@ -604,9 +705,10 @@ def _display(stdscr, proxmox, instance):
|
||||
warnung = ["Dafuer muss %s neu starten - die Grafikkarte laesst sich "
|
||||
"im Betrieb nicht wechseln." % instance.label,
|
||||
"",
|
||||
"Der Neustart laeuft sauber: Proxmox faehrt den Gast per ACPI "
|
||||
"herunter, er haengt seine Dateisysteme selbst aus, danach "
|
||||
"geht er wieder hoch. Kein Stromausfall.",
|
||||
"Gleich kannst du waehlen, wie: entweder du faehrst im Gast "
|
||||
"selbst herunter und pvesnap startet ihn danach wieder, oder "
|
||||
"Proxmox versucht es per ACPI. Der erste Weg ist der "
|
||||
"verlaesslichere - Windows ignoriert den Aus-Knopf gern.",
|
||||
"",
|
||||
"Ein Neustart von innen im Gast wuerde nichts bringen - dabei "
|
||||
"setzt sich nur die Maschine zurueck, der QEMU-Prozess laeuft "
|
||||
@@ -633,12 +735,8 @@ def _display(stdscr, proxmox, instance):
|
||||
if not geaendert:
|
||||
message(stdscr, "War schon so eingestellt.")
|
||||
return
|
||||
if neustart and confirm(stdscr, "%s jetzt sauber neu starten?" % instance.label):
|
||||
_do(stdscr, "Fahre %s herunter und wieder hoch ..." % instance.label,
|
||||
lambda: proxmox.reboot_guest(instance.guest))
|
||||
elif neustart:
|
||||
message(stdscr, "Eingetragen - wirksam beim naechsten Start. Im Gast "
|
||||
"herunterfahren, dann hier mit s starten.")
|
||||
if neustart:
|
||||
_neu_starten(stdscr, proxmox, instance)
|
||||
else:
|
||||
message(stdscr, "Uebernommen.")
|
||||
|
||||
@@ -796,8 +894,7 @@ def _overview(stdscr, proxmox):
|
||||
lambda: start(proxmox, current))
|
||||
reload_ = True
|
||||
elif key in ("h", "H"):
|
||||
_do(stdscr, "Fahre %s herunter ..." % current.label,
|
||||
lambda: proxmox.shutdown_guest(current.guest))
|
||||
_herunterfahren(stdscr, proxmox, current)
|
||||
reload_ = True
|
||||
elif key in ("x", "X"):
|
||||
_destroy(stdscr, proxmox, current)
|
||||
|
||||
Reference in New Issue
Block a user