recover: -y durfte die Warnung vor dem laufenden Original wegwinken
-y soll Routinefragen sparen, nicht die eine Frage abschalten, bei der es
weh tut. Der Fall "Original laeuft und die Wiederherstellung geht mit
denselben MAC-Adressen ans Netz" ist jetzt als kritisch gefuehrt:
-y wird abgewiesen (Exit 2), Hinweis auf --force
interaktiv das Wort "ja" muss ausgeschrieben werden, "j" reicht nicht
--force laeuft durch
Oberflaeche zweite Rueckfrage, die den Grund beim Namen nennt statt
nur "Warnungen gelesen?" zu fragen
Ausserdem wird stdout vor der Fehlerausgabe geleert - sonst stand die
Begruendung beim Umleiten ueber dem, worauf sie sich bezieht.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3ee5cf3508
commit
dc5c7d417f
@@ -681,11 +681,20 @@ Hier bleibt alles erhalten, was die Maschine ausmacht: SMBIOS-UUID, `vmgenid`,
|
|||||||
MAC-Adressen, bei Containern der Hostname. Für alles im Netz ist sie dieselbe
|
MAC-Adressen, bei Containern der Hostname. Für alles im Netz ist sie dieselbe
|
||||||
Maschine — inklusive Lizenzbindungen, AD-Mitgliedschaft und DHCP-Reservierungen.
|
Maschine — inklusive Lizenzbindungen, AD-Mitgliedschaft und DHCP-Reservierungen.
|
||||||
|
|
||||||
**Genau deshalb ist sie gefährlich.** `pvesnap-recovery` prüft vorher, ob das
|
**Genau deshalb ist sie gefährlich.** Zwei Maschinen mit derselben MAC und
|
||||||
Original läuft, und warnt unmissverständlich. Zwei Maschinen mit derselben MAC
|
derselben IP im selben Netz geben Chaos. `pvesnap-recovery` prüft deshalb
|
||||||
und derselben IP im selben Netz geben Chaos. Das Original also **vorher
|
vorher, ob das Original läuft, und lässt sich in dem Fall nicht beiläufig
|
||||||
stoppen** — oder mit `--net down` starten und die Karte erst zuschalten, wenn
|
durchwinken:
|
||||||
klar ist, dass die Luft rein ist.
|
|
||||||
|
| Situation | Verhalten |
|
||||||
|
|---|---|
|
||||||
|
| ncurses-Oberfläche | Zusammenfassung nur mit `j`, danach eine zweite Rückfrage, die den Grund beim Namen nennt |
|
||||||
|
| `recover …` im Terminal | das Wort **`ja`** muss ausgeschrieben werden — `j` reicht nicht |
|
||||||
|
| `recover … -y` | **wird abgewiesen** (Exit-Code 2). `-y` überspringt Routinefragen, nicht diese |
|
||||||
|
| `recover … --force` | läuft durch — die bewusste Entscheidung |
|
||||||
|
|
||||||
|
Das Original also **vorher stoppen** — oder mit `--net down` starten und die
|
||||||
|
Karte erst zuschalten, wenn klar ist, dass die Luft rein ist.
|
||||||
|
|
||||||
### Parameter
|
### Parameter
|
||||||
|
|
||||||
@@ -705,7 +714,8 @@ klar ist, dass die Luft rein ist.
|
|||||||
| `--name <name>` | Name der neuen Maschine |
|
| `--name <name>` | Name der neuen Maschine |
|
||||||
| `--keep-binds` | durchgereichte Host-Verzeichnisse des Originals übernehmen |
|
| `--keep-binds` | durchgereichte Host-Verzeichnisse des Originals übernehmen |
|
||||||
| `--no-start` | nur einrichten, nicht starten |
|
| `--no-start` | nur einrichten, nicht starten |
|
||||||
| `-y`, `--yes` | nicht nachfragen |
|
| `-y`, `--yes` | Routinefragen überspringen (deckt `--force` **nicht** ab) |
|
||||||
|
| `--force` | auch anlegen, wenn das Original noch läuft |
|
||||||
|
|
||||||
| Befehl | Bedeutung |
|
| Befehl | Bedeutung |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|||||||
+4
-1
@@ -307,6 +307,9 @@ class Plan:
|
|||||||
exchange_kind: str = "" # "disk" | "bind" | ""
|
exchange_kind: str = "" # "disk" | "bind" | ""
|
||||||
exchange_detail: str = ""
|
exchange_detail: str = ""
|
||||||
warnings: list = field(default_factory=list)
|
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.
|
||||||
|
critical: list = field(default_factory=list)
|
||||||
notes: list = field(default_factory=list)
|
notes: list = field(default_factory=list)
|
||||||
dropped: list = field(default_factory=list)
|
dropped: list = field(default_factory=list)
|
||||||
|
|
||||||
@@ -559,7 +562,7 @@ def plan(proxmox, guest, snapname, spec):
|
|||||||
"MAC-Adressen wie das Original.")
|
"MAC-Adressen wie das Original.")
|
||||||
status = proxmox.guest_status(guest)
|
status = proxmox.guest_status(guest)
|
||||||
if status.get("status") == "running":
|
if status.get("status") == "running":
|
||||||
result.warnings.append(
|
result.critical.append(
|
||||||
"%s LAEUFT gerade. Zwei Maschinen mit gleicher MAC-Adresse, "
|
"%s LAEUFT gerade. Zwei Maschinen mit gleicher MAC-Adresse, "
|
||||||
"gleicher IP und gleicher Identitaet im selben Netz geben Chaos - "
|
"gleicher IP und gleicher Identitaet im selben Netz geben Chaos - "
|
||||||
"erst das Original stoppen." % guest.label)
|
"erst das Original stoppen." % guest.label)
|
||||||
|
|||||||
+37
-7
@@ -338,11 +338,10 @@ def summary_lines(plan_):
|
|||||||
for note in plan_.notes:
|
for note in plan_.notes:
|
||||||
for line in _wrap("- " + note, 74):
|
for line in _wrap("- " + note, 74):
|
||||||
lines.append((line, curses.color_pair(C_DIM)))
|
lines.append((line, curses.color_pair(C_DIM)))
|
||||||
if plan_.warnings:
|
for entry in plan_.warnings + plan_.critical:
|
||||||
lines.append(("", 0))
|
lines.append(("", 0))
|
||||||
for warning in plan_.warnings:
|
for line in _wrap("!! " + entry, 74):
|
||||||
for line in _wrap("!! " + warning, 74):
|
lines.append((line, curses.color_pair(C_WARN) | curses.A_BOLD))
|
||||||
lines.append((line, curses.color_pair(C_WARN) | curses.A_BOLD))
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
@@ -396,7 +395,13 @@ def _new(stdscr, proxmox):
|
|||||||
"j = anlegen | beliebige andere Taste = zurueck")
|
"j = anlegen | beliebige andere Taste = zurueck")
|
||||||
if key not in ("j", "J", "y", "Y"):
|
if key not in ("j", "J", "y", "Y"):
|
||||||
continue
|
continue
|
||||||
if plan_.warnings and not confirm(
|
if plan_.critical:
|
||||||
|
# Beim Namen nennen, worum es geht - "Warnungen gelesen?"
|
||||||
|
# klickt man weg, ohne hinzusehen.
|
||||||
|
if not confirm(stdscr, truncate(plan_.critical[0], 60)
|
||||||
|
+ " Trotzdem?"):
|
||||||
|
continue
|
||||||
|
elif plan_.warnings and not confirm(
|
||||||
stdscr, "Warnungen gelesen und trotzdem anlegen?"):
|
stdscr, "Warnungen gelesen und trotzdem anlegen?"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -694,6 +699,8 @@ def _print_summary(plan_):
|
|||||||
print(" Hinweis : %s" % note)
|
print(" Hinweis : %s" % note)
|
||||||
for warning in plan_.warnings:
|
for warning in plan_.warnings:
|
||||||
print(" ACHTUNG : %s" % warning)
|
print(" ACHTUNG : %s" % warning)
|
||||||
|
for reason in plan_.critical:
|
||||||
|
print(" GEFAHR : %s" % reason)
|
||||||
|
|
||||||
|
|
||||||
def cmd_create(proxmox, args, mode):
|
def cmd_create(proxmox, args, mode):
|
||||||
@@ -704,7 +711,26 @@ def cmd_create(proxmox, args, mode):
|
|||||||
|
|
||||||
print("Vorhaben:")
|
print("Vorhaben:")
|
||||||
_print_summary(plan_)
|
_print_summary(plan_)
|
||||||
if not args.yes:
|
|
||||||
|
# Gefaehrliches laesst sich nicht mit -y wegwinken. -y heisst "keine
|
||||||
|
# Routinefragen", nicht "frag mich auch dann nicht, wenn es weh tut".
|
||||||
|
if plan_.critical and not args.force:
|
||||||
|
# Sonst ueberholt die Fehlerausgabe die gepufferte Zusammenfassung,
|
||||||
|
# sobald jemand die Ausgabe umleitet - und die Begruendung stuende
|
||||||
|
# ueber dem, worauf sie sich bezieht.
|
||||||
|
sys.stdout.flush()
|
||||||
|
print("\nDas geht so nicht:", file=sys.stderr)
|
||||||
|
for reason in plan_.critical:
|
||||||
|
print(" - %s" % reason, file=sys.stderr)
|
||||||
|
if args.yes:
|
||||||
|
print("\n-y reicht dafuer nicht. Entweder das Original stoppen oder\n"
|
||||||
|
"bewusst --force setzen.", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
print("\nWer das trotzdem will, tippt jetzt das Wort ja aus.")
|
||||||
|
if input("Trotzdem anlegen? [ja/nein] ").strip().lower() not in ("ja", "yes"):
|
||||||
|
print("Abgebrochen.")
|
||||||
|
return 1
|
||||||
|
elif not args.yes:
|
||||||
if plan_.warnings:
|
if plan_.warnings:
|
||||||
print("\nEs gibt Warnungen - bitte oben lesen.")
|
print("\nEs gibt Warnungen - bitte oben lesen.")
|
||||||
answer = input("\nAnlegen? [j/N] ").strip().lower()
|
answer = input("\nAnlegen? [j/N] ").strip().lower()
|
||||||
@@ -834,7 +860,11 @@ def _add_create_options(parser):
|
|||||||
"uebernehmen (Vorgabe: weglassen)")
|
"uebernehmen (Vorgabe: weglassen)")
|
||||||
parser.add_argument("--no-start", action="store_true",
|
parser.add_argument("--no-start", action="store_true",
|
||||||
help="nur einrichten, nicht starten")
|
help="nur einrichten, nicht starten")
|
||||||
parser.add_argument("-y", "--yes", action="store_true", help="nicht nachfragen")
|
parser.add_argument("-y", "--yes", action="store_true",
|
||||||
|
help="Routinefragen ueberspringen (deckt --force nicht ab)")
|
||||||
|
parser.add_argument("--force", action="store_true",
|
||||||
|
help="auch dann anlegen, wenn das Original noch laeuft - "
|
||||||
|
"gleiche MAC und IP zweimal im Netz")
|
||||||
|
|
||||||
|
|
||||||
def build_parser():
|
def build_parser():
|
||||||
|
|||||||
Reference in New Issue
Block a user