Close three gaps before they become three bugs in the script
Read on review, before a line of shell was written. All three would have been found on hardware instead — two of them late, and one of them only by noticing something that was silently absent. The progress file did not survive the reboot. Task 1 writes it in the rescue system, whose root lives in RAM; Task 3 installs Debian and reboots. The plan said the resuming service uses "the same progress file" without saying how it gets there. Because flush_reports first runs in Task 6, AFTER the reboot, rescue_checked and debian_installed would simply never have reached the console — and nothing would have pointed at the reboot as the reason. Task 3 now carries the file, the script, and the arguments across, the last one root-readable only because the WireGuard key is in it. RebootIntoPveKernel.php was on the platform plan's delete list but not on this plan's read list. Six files were named; seven are deleted. This is the one that proves the boot path BEFORE issuing the one irreversible command in the whole run: a -pve kernel image present, its initramfs present (a full /boot leaves exactly the half-written one), and update-grub checked on its exit status, which its predecessor discarded. Losing that would have cost a machine that does not come back, and on a dedicated server that means the provider's console. Reading it also corrected a rule this plan states. Task 9 rightly refuses `pveum ... || true`, but that is not a rule against `|| true` — RebootIntoPveKernel tolerates one deliberately, with the reason written next to it, and a script that applies the ban literally breaks the kernel removal in Task 3. The rule is now stated as what it is: no `|| true` over a command whose failure means something. The key swap in Task 9 had no proven handshake. Task 6 insists a tunnel counts only with one, then Task 9 re-keys that same tunnel and discards the old key on ordering alone. Ordering says when to discard, not whether the new key carries. Four numbered steps now, with the proof third and the discard fourth, and a fallback to the old key if the handshake does not come — the one failure nobody fixes remotely, at the end of a run that did everything else right. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>feature/host-bootstrap
parent
fe07fa2e77
commit
61c2501136
|
|
@ -13,6 +13,17 @@
|
|||
- **Vollfassung des Entwurfs:** `docs/superpowers/specs/2026-07-30-host-uebernahme-statt-installation-design.md`. Bei Widerspruch gewinnt die Spec.
|
||||
- **DIE WICHTIGSTE AUFLAGE: das Wissen liegt schon im Repository, erfinde es nicht neu.** Die heutigen Pipeline-Schritte enthalten alles, was hier gebraucht wird — und sie werden vom Plattform-Plan **gelöscht**. Lies sie, **bevor** das passiert:
|
||||
- `app/Provisioning/Steps/Host/InstallProxmoxVe.php` — die Codename-Tabelle (Debian 13/trixie ↔ PVE 9), die Paketquellen, die Reihenfolge. Der Handoff hält fest, dass ein fest verdrahtetes `bookworm` heute PVE-8-Quellen gegen Debian 13 gesetzt hätte.
|
||||
- `app/Provisioning/Steps/Host/RebootIntoPveKernel.php` — **der Neustart ist das
|
||||
einzige Unumkehrbare am ganzen Vorgang.** Die Datei beweist den Bootpfad,
|
||||
*bevor* sie neu startet, statt ihn aus „apt hat nicht gemeckert" zu
|
||||
schließen: `/boot/vmlinuz-*-pve` vorhanden, `/boot/initrd.img-*-pve`
|
||||
vorhanden (ein volles `/boot` hinterlässt genau die halbe Initramfs), und
|
||||
`update-grub` **an seinem Exit-Status** geprüft — den der Vorgänger verwarf.
|
||||
Alle drei scheitern hart statt zu wiederholen, weil keine sich von selbst
|
||||
behebt. Dazu die 15-Minuten-Frist, die ihre eigenen Marker löscht, damit ein
|
||||
Wiederholungslauf frisch neu startet statt sofort wieder in die abgelaufene
|
||||
Frist zu laufen. **Diese Datei stand nicht in der ersten Fassung dieser
|
||||
Liste, steht aber auf der Löschliste des Plattform-Plans.**
|
||||
- `app/Provisioning/Steps/Host/ConfigureProxmox.php` — die vollständige Diagnose zu `vmbr0`: warum Proxmox auf Debian keine anlegt, was eine falsche Brücke anrichtet, und die Datacenter-Firewall, ohne die die „nur 80/443"-Regeln der Kunden-VMs **wirkungslos** sind.
|
||||
- `app/Provisioning/Steps/Host/SecureHostFirewall.php` — die nftables-Regeln, samt der Korrektur, dass **nicht jedes ICMP** verworfen werden darf (sonst sind IPv6 und PMTUD gebrochen).
|
||||
- `app/Provisioning/Steps/Host/ConfigureWireguard.php` — wie `wg0` systemd-aktiviert wird. Der Handoff hält fest, dass ein `||`-Rückfall die fehlende Aktivierung verdeckte und der Neustart eine nicht mehr bootende Maschine hinterlassen konnte.
|
||||
|
|
@ -118,8 +129,30 @@ Der Neustart ist die erste Stelle, an der das Skript die Kontrolle verliert. Es
|
|||
hinterlässt deshalb einen systemd-Dienst, der es nach dem Hochfahren **selbst
|
||||
wieder aufnimmt** — mit demselben Code und derselben Fortschrittsdatei.
|
||||
|
||||
**Und genau das ist der Punkt, an dem „dieselbe Fortschrittsdatei" Arbeit ist und
|
||||
keine Feststellung.** Das Rettungssystem läuft im Arbeitsspeicher; sein
|
||||
Wurzelverzeichnis ist nach dem Neustart weg. Bevor neu gestartet wird, gehen
|
||||
deshalb **in das frisch installierte System hinüber**:
|
||||
|
||||
- `/var/lib/clupilot/progress.jsonl` — sonst gehen `rescue_checked` und
|
||||
`debian_installed` verloren.
|
||||
- das Skript selbst samt `lib/`,
|
||||
- die Aufrufargumente aus Task 1, in einer Datei, die nur `root` lesen kann —
|
||||
der WireGuard-Schlüssel steht darin.
|
||||
|
||||
Ohne diesen Handgriff meldet das Skript nach dem Neustart bei Null. Und weil
|
||||
`flush_reports` erst in Task 6 läuft, **also nach dem Neustart**, fiele der
|
||||
Verlust nirgends auf — die zwei Abschnitte kämen in der Konsole schlicht nie an.
|
||||
Genau das prüft Task 6 Step 2, wenn er **alle fünf** vorherigen Abschnitte
|
||||
verlangt.
|
||||
|
||||
Zum Neustart selbst: **lies `RebootIntoPveKernel.php`.** Der Bootpfad wird
|
||||
bewiesen, bevor neu gestartet wird, nicht danach gehofft.
|
||||
|
||||
- [ ] **Step 2: Auf echter Hardware prüfen** — und ausdrücklich, dass es nach dem
|
||||
Neustart von allein weiterläuft.
|
||||
Neustart von allein weiterläuft. **Dazu: nach dem Hochfahren in
|
||||
`/var/lib/clupilot/progress.jsonl` nachsehen, dass die Zeilen von *vor* dem
|
||||
Neustart noch dort stehen, mit ihren ursprünglichen Zeitstempeln.**
|
||||
- [ ] **Step 3: Committen.** `Write Debian and survive the first reboot`
|
||||
|
||||
---
|
||||
|
|
@ -260,13 +293,41 @@ Eckdaten. Die Antwort trägt das dauerhafte Host-Token für Traefik.
|
|||
verwerfen. Die Gegenseite nimmt erst auf und entfernt dann — aber das Skript darf
|
||||
sich auch von seiner Seite nicht vorzeitig abschneiden.
|
||||
|
||||
**Und der Tausch braucht denselben Beweis wie der Beitritt.** Task 6 lässt den
|
||||
Tunnel erst mit bewiesenem Handshake gelten; hier wird genau dieser Tunnel unter
|
||||
laufendem Betrieb auf einen neuen Schlüssel umgestellt. Die Reihenfolge allein
|
||||
schützt davor nicht — sie sagt nur, wann verworfen wird, nicht ob das Neue
|
||||
trägt. Deshalb, in dieser Folge:
|
||||
|
||||
1. neues Schlüsselpaar erzeugen, registrieren, Antwort haben,
|
||||
2. `wg0` auf den neuen privaten Schlüssel umstellen,
|
||||
3. **erneuten Handshake beweisen** — dieselbe Prüfung wie in Task 6, nicht die
|
||||
geschriebene Datei,
|
||||
4. **erst dann** den alten Schlüssel verwerfen.
|
||||
|
||||
Kommt der Handshake nicht, wird auf den alten Schlüssel zurückgestellt und der
|
||||
Abschnitt scheitert laut. Ein Host, der sich im letzten Schritt selbst
|
||||
aussperrt, ist der eine Fall, den niemand aus der Ferne repariert — und er
|
||||
passiert am Ende eines Laufs, der bis dahin alles richtig gemacht hat.
|
||||
|
||||
Zum Schluss: `pveum acl modify … || true` und `pveum user add … || true`
|
||||
**nicht** übernehmen. Der Handoff nennt sie als offenen Punkt — sie verdecken
|
||||
Fehler, dieselbe Klasse wie der bereits behobene `role add`.
|
||||
|
||||
Das ist aber **keine Regel gegen `|| true` an sich**, und wer sie so liest,
|
||||
bricht Task 3. `RebootIntoPveKernel.php` toleriert
|
||||
`apt-get -y remove linux-image-amd64 || true` **mit Begründung**: ein Image, das
|
||||
das Metapaket nie hatte, lässt apt ohne Fehler in der Sache von Null verschieden
|
||||
enden — und ob der Debian-Kernel weg ist, ist ohnehin nicht die Frage, sondern
|
||||
ob ein Proxmox-Kernel bootet, was drei Zeilen später eigenständig geprüft wird.
|
||||
Die Regel lautet: **kein `|| true` über einem Befehl, dessen Fehlschlag etwas
|
||||
bedeutet** — und wo eines steht, steht der Grund daneben.
|
||||
|
||||
- [ ] **Step 2: Auf echter Hardware prüfen.** Der Host steht in der Konsole auf
|
||||
`active`, die sechs Schritte der Kette laufen durch, und die Bereitschaftsseite
|
||||
meldet `provisioning.usable_host` als erfüllt.
|
||||
meldet `provisioning.usable_host` als erfüllt. **Und der Tunnel steht danach
|
||||
noch** — nach dem Schlüsseltausch einmal `wg show` ansehen und einen frischen
|
||||
Handshake mit dem *neuen* Schlüssel sehen, nicht den alten Zählerstand.
|
||||
- [ ] **Step 3: Committen.** `Hand over the token and let the console take it from here`
|
||||
|
||||
---
|
||||
|
|
|
|||
Loading…
Reference in New Issue