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
|
||||
Maschine — inklusive Lizenzbindungen, AD-Mitgliedschaft und DHCP-Reservierungen.
|
||||
|
||||
**Genau deshalb ist sie gefährlich.** `pvesnap-recovery` prüft vorher, ob das
|
||||
Original läuft, und warnt unmissverständlich. Zwei Maschinen mit derselben MAC
|
||||
und derselben IP im selben Netz geben Chaos. Das Original also **vorher
|
||||
stoppen** — oder mit `--net down` starten und die Karte erst zuschalten, wenn
|
||||
klar ist, dass die Luft rein ist.
|
||||
**Genau deshalb ist sie gefährlich.** Zwei Maschinen mit derselben MAC und
|
||||
derselben IP im selben Netz geben Chaos. `pvesnap-recovery` prüft deshalb
|
||||
vorher, ob das Original läuft, und lässt sich in dem Fall nicht beiläufig
|
||||
durchwinken:
|
||||
|
||||
| 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
|
||||
|
||||
@@ -705,7 +714,8 @@ klar ist, dass die Luft rein ist.
|
||||
| `--name <name>` | Name der neuen Maschine |
|
||||
| `--keep-binds` | durchgereichte Host-Verzeichnisse des Originals übernehmen |
|
||||
| `--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 |
|
||||
|---|---|
|
||||
|
||||
+4
-1
@@ -307,6 +307,9 @@ class Plan:
|
||||
exchange_kind: str = "" # "disk" | "bind" | ""
|
||||
exchange_detail: 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.
|
||||
critical: list = field(default_factory=list)
|
||||
notes: 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.")
|
||||
status = proxmox.guest_status(guest)
|
||||
if status.get("status") == "running":
|
||||
result.warnings.append(
|
||||
result.critical.append(
|
||||
"%s LAEUFT gerade. Zwei Maschinen mit gleicher MAC-Adresse, "
|
||||
"gleicher IP und gleicher Identitaet im selben Netz geben Chaos - "
|
||||
"erst das Original stoppen." % guest.label)
|
||||
|
||||
+37
-7
@@ -338,11 +338,10 @@ def summary_lines(plan_):
|
||||
for note in plan_.notes:
|
||||
for line in _wrap("- " + note, 74):
|
||||
lines.append((line, curses.color_pair(C_DIM)))
|
||||
if plan_.warnings:
|
||||
for entry in plan_.warnings + plan_.critical:
|
||||
lines.append(("", 0))
|
||||
for warning in plan_.warnings:
|
||||
for line in _wrap("!! " + warning, 74):
|
||||
lines.append((line, curses.color_pair(C_WARN) | curses.A_BOLD))
|
||||
for line in _wrap("!! " + entry, 74):
|
||||
lines.append((line, curses.color_pair(C_WARN) | curses.A_BOLD))
|
||||
return lines
|
||||
|
||||
|
||||
@@ -396,7 +395,13 @@ def _new(stdscr, proxmox):
|
||||
"j = anlegen | beliebige andere Taste = zurueck")
|
||||
if key not in ("j", "J", "y", "Y"):
|
||||
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?"):
|
||||
continue
|
||||
|
||||
@@ -694,6 +699,8 @@ def _print_summary(plan_):
|
||||
print(" Hinweis : %s" % note)
|
||||
for warning in plan_.warnings:
|
||||
print(" ACHTUNG : %s" % warning)
|
||||
for reason in plan_.critical:
|
||||
print(" GEFAHR : %s" % reason)
|
||||
|
||||
|
||||
def cmd_create(proxmox, args, mode):
|
||||
@@ -704,7 +711,26 @@ def cmd_create(proxmox, args, mode):
|
||||
|
||||
print("Vorhaben:")
|
||||
_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:
|
||||
print("\nEs gibt Warnungen - bitte oben lesen.")
|
||||
answer = input("\nAnlegen? [j/N] ").strip().lower()
|
||||
@@ -834,7 +860,11 @@ def _add_create_options(parser):
|
||||
"uebernehmen (Vorgabe: weglassen)")
|
||||
parser.add_argument("--no-start", action="store_true",
|
||||
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():
|
||||
|
||||
Reference in New Issue
Block a user