Live auf echter Hardware gefunden (01.09.2026): "Error: Partition(s) 1
on /dev/sda have been written, but we have been unable to inform the
Kernel of the change, probably because it/they are in use." - parted
schreibt die neue GPT-Tabelle zwar trotzdem, meldet aber einen Fehler,
wenn eine alte Partition (Swap, gemountetes Dateisystem vom vorherigen
Betriebssystem auf dieser Platte) noch belegt ist. In QEMU mit stets
frischen Testplatten nie aufgetreten - reale Kundenhardware hat aber
fast immer schon ein Vorleben auf der Platte.
Zwei neue Bausteine in image_deploy_partition():
- _image_deploy_release_disk(): unmountet/deaktiviert Swap auf allen
vorhandenen Partitionen der Zielplatte, bevor ueberhaupt mklabel
aufgerufen wird.
- _image_deploy_settle_partitions(): wiederholt partprobe/udevadm settle
bis zu 5x statt nach einem einzigen Versuch aufzugeben, sowohl nach
mklabel als auch nach dem Anlegen der eigentlichen Partitionen.
Zusaetzlich wird nach mklabel explizit verifiziert, dass wirklich ein
gueltiges GPT-Label vorliegt (parted print), statt parteds Exit-Code
fuer den Kernel-Info-Schritt blind als Gesamtfehlschlag zu werten.
Lokal verifiziert: einmal komplett durchinstalliert (frische Platte),
dann OHNE die Platte zurueckzusetzen ein zweites Mal auf dieselbe,
bereits mit einem echten System belegte Platte installiert - lief
sauber durch, keine Kernel-Fehlermeldung mehr.
Live auf echter Hardware gefunden (01.09.2026): eine vorkonfigurierte SSID
war im Moment des Scans nicht sichtbar (Kunde stand ungluenstig, das
eigene Handy war im selben WLAN aber verbunden) - bisher brach
05_network.sh beim ersten Fehlschlag sofort fatal ab, ohne dem Kunden
eine Chance zu geben, den Standort zu wechseln oder ein Netzwerkkabel
einzustecken.
Neue establish_network_connection()-Schleife (Default: 10 Versuche,
15s Pause, beides per TUXFLOTTE_NETWORK_MAX_ATTEMPTS/
TUXFLOTTE_NETWORK_RETRY_DELAY konfigurierbar) wiederholt bei jedem
Versuch die KOMPLETTE Erkennung von vorne (nicht nur WLAN erneut) -
damit wird auch ein waehrend der Wartezeit eingestecktes Netzwerkkabel
erkannt, nicht nur ein erneuter WLAN-Versuch.
Lokal in der enterprise-QEMU-VM verifiziert: Netzwerk-Link waehrend des
Boots per virsh domif-setlink kurzzeitig deaktiviert - Retry-Meldung
"Verbindungsversuch 1/10 fehlgeschlagen..." erschien korrekt, nach
Wiederherstellen des Links lief der Installer beim naechsten Versuch
automatisch weiter bis zur Golden-Image-Installation.
Live auf echter Hardware gefunden (01.09.2026), direkt nachdem der
vorige LXC-Fix (Commit f6bb3db) deployed wurde: "-excludes dev" entfernt
nicht nur die Geraetedateien, sondern das gesamte /dev-Verzeichnis.
live-boots eigenes Initramfs-Skript braucht /dev aber als reinen
Mountpunkt (bindet dort sein eigenes Devtmpfs ein, kurz vor
switch_root) und scheiterte deshalb sofort beim Booten mit "mount:
/root/dev: mount point does not exist", gefolgt von einem Kernel-Panic.
Fix: mkdir -p nach dem Entpacken stellt /dev als leeres Verzeichnis
wieder her - devtmpfs bindet sich selbst darueber, die eigentlichen
Geraetedateien werden nie aus dem Squashfs gebraucht. Dasselbe Muster
wie image_deploy_restore_excluded_dirs() beim Golden Image, nur hier
fuers Boot-Medium selbst.
Diesmal VOR dem Deploy lokal in der enterprise-QEMU-VM boot-getestet
(der vorige Fix wurde ungetestet deployed, was genau zu diesem Bug
fuehrte) - sauberer Boot bestaetigt, kein Kernel-Panic, Auto-Modus laeuft
bis zur Golden-Image-Installation durch.
Live gefunden (01.09.2026, erster echter Produktionslauf ueber die reale
Kundenplattform-API): anode laeuft in einem LXC-Container
(systemd-detect-virt: lxc), der CAP_MKNOD grundsaetzlich blockiert - auch
fuer root. unsquashfs scheiterte beim Wiederherstellen der wenigen
Geraetedateien im Boot-Medium-Squashfs (/dev/null, /dev/console, ...) mit
"Operation not permitted", ISO-Bau brach ab.
"-excludes ... dev" schliesst /dev komplett von der Extraktion aus -
anders als beim Golden Image (package_golden_image.sh) ist das hier
unkritisch: das Boot-Medium ist nur der Installations-Vermittler, nicht
das ausgelieferte System - devtmpfs erzeugt /dev beim tatsaechlichen Boot
ohnehin automatisch neu.
Zugehoerige Produktions-Deployment-Schritte (nicht im Diff sichtbar):
main auf anode gepullt (war noch auf dem alten bc9cefa-Stand vor dem
gesamten Boot-Medium-Umbau), squashfs-tools installiert (fehlte), neues
Basis-ISO nach data/upstream/tuxflotte-mint-boot-medium.iso hochgeladen,
TUXFLOTTE_MINT_ISO_PATH in provisioning-server.env gesetzt, Dienst neu
gestartet.
Entfernt (Historie bleibt ueber Git-Log erhalten, siehe ADR-0025 in
platform-docs fuer die vollstaendige Begruendung/den Gesamtrueckblick):
- backends/mint/ (Ubiquity-Preseed-Backend, backend_launch()-Pfad nicht
mehr referenziert seit Phase 1, postinstall.sh dort bereits migriert)
- scripts/lib/initrd.sh, initrd-hooks/ (Casper-Bottom-Hook-Injection,
nur fuer das Patchen einer fremden fertigen Mint-ISO noetig)
- grub/mint-boot-grub.cfg, grub/mint-isolinux-live.cfg
- live-updates/ (Cinnamon-Kiosk, AT-SPI-Autoklicker)
scripts/build.sh (das alte Test-Build-Skript) bedient jetzt nur noch das
Fedora-Backend (Kickstart/Anaconda, unveraendert, ausserhalb dieses
Plans) - Mint-Zweig entfernt (bake_test_preseed(), patch_initrd(),
initrd.sh-Source, mint-spezifische GRUB-Pfade). Die unbedingte
live-updates/-Kopie in prepare_updates() entfiel ebenfalls - sie wurde
fuer Fedora nie inhaltlich gebraucht (Anaconda/Kickstart kennt kein
Cinnamon-Kiosk/keinen AT-SPI-Autoklicker), nur bisher blind mitkopiert.
README.md um einen Abschnitt zum neuen Boot-Medium-Bauweg ergaenzt
(build_boot_medium.sh/build_customer_iso.sh vs. weiterhin
Fedora-spezifisches build.sh).
Fuenfter und letzter live gefundener Bug auf dem Weg zum ersten
vollstaendig erfolgreichen End-to-End-Deployment: die echte
Mint-Referenz-VM bringt jq nicht mit (anders als das Boot-Medium selbst,
das hilft dem chroot-Zielsystem aber nicht - komplett eigener Kontext).
postinstall.sh scheiterte deshalb an "jq: command not found". curl/python3
gleich mit abgesichert (python3 wird vom heruntergeladenen agent.py nach
dem naechsten Boot gebraucht), um nicht noch einen ganzen
Referenz-VM-Neupack-Zyklus wegen eines weiteren fehlenden Pakets zu
riskieren. apt-get update noetig, da package_golden_image.sh
/var/lib/apt/lists als Teil der Bereinigung leert.
Damit lief der komplette Self-Service-Flow zum ersten Mal vollstaendig
durch: Enrollment-Session -> personalisiertes ISO -> Boot -> Partition/
Format/Mount -> Golden-Image-Stream-Download+Extraktion -> chroot-Fixup
-> Bootloader -> Postinstall/Agent-Bootstrap -> Reboot -> echter
Linux-Mint-Cinnamon-Login-Bildschirm (Hostname "debian", deutsches
Tastaturlayout aktiv). agent_secret_issued_at in der Datenbank bestaetigt
die erfolgreiche Agent-Registrierung bei anode.
Damit sind alle vier Phasen des Boot-Medium-Plans live end-to-end
verifiziert. Voraussetzung dafuer: das golden-image-Archiv auf anode
wurde mit dem korrigierten package_golden_image.sh (vorheriger Commit)
neu gepackt (4,8 GB statt 2,3 GB, jetzt mit den vorher fehlenden
Kernelmodulen) und live ersetzt - alte Version als
linux-mint-22.3-cinnamon.tar.zst.defekt-31.08.bak gesichert.
Phase 3: Personalisierung (Aktivierungscode/WLAN) funktioniert jetzt ohne
Xorriso-Extraktion der ganzen ISO / Casper-Hook-Injection. /opt/tuxflotte/
liegt innerhalb von /live/filesystem.squashfs (read-only) - ein direktes
xorriso -update auf eine Datei darin traf live getestet ins Leere.
Stattdessen: Squashfs entpacken (unsquashfs), installer.conf ersetzen, neu
packen (mksquashfs -comp xz, ~1 Minute reine Kompression, kein
debootstrap/apt), als Ganzes per xorriso -update einspielen. Muss als root
laufen (Datei-Eigentuemer im Squashfs sonst falsch).
Beim ersten echten End-to-End-Testlauf mit dem vollen Golden-Image-Archiv
(vorher nie bis zum Ende gekommen - immer am Ubiquity-Bug oder an einem
Commit-Gate gestoppt) vier echte, bisher unentdeckte Bugs gefunden und
behoben:
1. Golden-Image-Download landete in /run/tuxflotte/backend/ (RAM-Tmpfs,
hier 392 MB) statt auf echtem Speicher - "curl: (23) Failure writing
output to destination" bei 2,3 GB Archiv, unabhaengig von RAM-Groesse.
Fix: image_deploy_extract_image_from_url() streamt Download direkt in
die Extraktion (curl | tar), kein Zwischenspeichern mehr noetig.
backend_launch() partitioniert/formatiert/mountet jetzt VOR dem
Download-Versuch statt danach.
2. /etc/resolv.conf im Zielbaum ist bei der echten Referenz-VM ein von
NetworkManager verwalteter Symlink - "cp" verweigerte das Schreiben
"through a dangling symlink". Fix: Ziel vor dem Kopieren explizit
entfernen.
3. mount --bind auf /dev, /proc, /sys schlug fehl, weil diese Verzeichnisse
nach dem Entpacken gar nicht existierten (package_golden_image.sh
schliesst sie bewusst aus) - und zwar SILENT, weil das bisherige
"cmd && stack_ref+=(...)"-Muster einen Fehlschlag unter "set -e" nicht
als Statement-Fehler wertet. Fiel dadurch erst beim naechsten
chroot-Aufruf auf ("ssh-keygen -A: Couldn't open /dev/null"), weit weg
von der eigentlichen Ursache. Fix: neue image_deploy_restore_excluded_dirs()
legt alle sechs von package_golden_image.sh ausgeschlossenen
Verzeichnisse (proc/sys/dev/run/tmp/var-tmp) direkt nach der Extraktion
wieder an; jeder Mount wird jetzt einzeln explizit geprueft statt auf
&&-Verkettung zu vertrauen.
4. package_golden_image.sh: "--exclude=dev" (ohne "./"-Praefix) matcht bei
GNU tar gegen JEDEN Verzeichnis-Basisnamen im ganzen Baum, nicht nur
den Top-Level-Eintrag - hat dadurch auch kernel/drivers/net/can/dev/
(ein zufaellig gleichnamiger, voellig unverwandter Kernelmodul-Ordner)
aus dem Archiv gerissen, update-initramfs scheiterte an fehlenden
can-dev.ko.zst-Abhaengigkeiten. Lokal mit einem Wegwerf-Testbaum
verifiziert (wie beim "run"-Fund vom selben Tag): "./"-Praefix
verankert das Muster auf den exakten Top-Level-Pfad, gleichnamige
verschachtelte Ordner bleiben erhalten. Betrifft das AKTUELL AUF ANODE
GEHOSTETE Archiv - muss mit dem korrigierten Skript auf der
Referenz-VM neu gepackt und hochgeladen werden (steht noch aus,
Nutzer verschlankt die Referenz-VM gerade zusaetzlich).
Live-Fortschritt in der enterprise-QEMU-VM: nach Fix 1-3 kam der
Deployment-Versuch bis kurz vor update-initramfs durch (Partitionierung,
Formatierung, Mounten, Download+Extraktion, chroot-Fixup bis machine-id +
SSH-Hostkeys liefen alle sauber) - Fund 4 (das defekte Archiv) ist der
letzte noch offene Blocker fuer einen vollstaendig erfolgreichen
End-to-End-Durchlauf.
80-Spalten-ASCII-Banner (pics/tuxflotte-terminal-80.txt, lose Asset-Datei,
nicht versioniert - pics/ ist kein Git-Repo) wird beim Boot vor
installer.sh angezeigt, sowohl im Dev- als auch im Produktiv-Build.
Schriftzug frisch per figlet (Font "big") erzeugt, passt sauber in 80
Spalten. Grafik-Teil aus der bestehenden 160-Spalten-Vorlage per
Spalten-Verdichtung (2:1) abgeleitet, da die Original-SVG-Logo-Konturen
(reine offene Pfade ohne Fill) bei 80 Spalten direkt aus dem Vektor
konvertiert nur noch vereinzelte Punkte ergeben - live geprueft, siehe
Konversation.
boot-autostart.sh zeigt das Banner nur wenn lesbar (if statt &&, sonst
wuerde ein fehlendes Banner das Skript unter set -e sofort beenden).
Live verifiziert in der enterprise-QEMU-VM: Banner erscheint korrekt vor
[1/12] Vorbereitung, passt vollstaendig in die 80-Spalten-Konsole.
Neuer Service tuxflotte-installer.service startet installer.sh beim Boot
direkt auf tty1 (Type=idle, Conflicts=getty@tty1.service) - kein manuelles
Anmelden/sudo mehr noetig, egal ob Auto-Modus oder interaktiver
Test-/Entwicklungslauf. Wrapper boot-autostart.sh spiegelt die Ausgabe
zusaetzlich nach /var/log/tuxflotte-installer.log.
log_step() (scripts/lib/logging.sh) gibt vor jedem Modul einen klar
abgesetzten "[n/12] <Label>"-Block aus - gilt fuer Dev- UND Produktiv-Build
gleichermassen (die tty-Konsole ist die einzige UI, die eine Person vor
dem Geraet sieht, kein Kiosk-Browser mehr).
scripts/build_boot_medium.sh buendelt lb clean/config/build (loeste die
bisherigen Hand-Aufrufe ab) und steuert per --dev-Flag einen SSH-
Debug-Zugang (tuxflotte/test123) - ohne --dev bleibt SSH deaktiviert,
keine gebackenen Zugangsdaten (Produktiv-Default).
Zwei echte, live gefundene Bugs unterwegs behoben:
- Debians trixie-sshd_config deaktiviert PasswordAuthentication per
Default - fuer den Dev-Testzugang explizit wieder aktiviert.
- Ein ExecStopPost, der getty@tty1.service nach Dienstende neu startet,
ist unzuverlaessig (Race mit dem eigenen TTY-Teardown, Job wurde
angestossen, blieb aber inactive/dead). Geloest durch einen
deterministischen Fallback in boot-autostart.sh selbst: die Konsole
faellt nach installer.sh in eine interaktive Shell statt auf einen
eventuell nie zurueckkehrenden getty zu warten.
Live verifiziert in der enterprise-QEMU-VM (zwei frische Enrollment-
Sessions, echte anode-Aktivierung, "Bekanntes Geraet erkannt"-Pfad):
Boot laeuft ohne jede manuelle Anmeldung direkt in installer.sh, alle
12 Fortschritts-Banner erscheinen korrekt nummeriert, Commit-Gate und
kontrollierter Abbruch funktionieren, SSH-Login mit Passwort
funktioniert, Fallback-Shell nach Programmende reagiert auf Eingaben.
scripts/ (installer.sh, lib/*, modules/00-99) und backends/mint-image/
(inkl. echtem postinstall.sh statt Symlink auf backends/mint/) werden ueber
config/includes.chroot/opt/tuxflotte/ ins Image kopiert - bewusst nur die
zur Laufzeit benoetigten Dateien, nicht die Build-Host-Werkzeuge
(build_customer_iso.sh, build_golden_image.sh, package_golden_image.sh,
lib/initrd.sh etc. bleiben aussen vor).
00_preflight.sh und backend_init() (backends/mint-image/backend.sh)
verlieren ihre Laufzeit-apt-get-Nachinstallation (jq, parted, dosfstools,
e2fsprogs, zstd, btrfs-progs, gettext-base, curl) - alles bereits in
Phase 0 vorinstalliert. Werden durch reine Assertions ersetzt, die frueh
und klar melden, falls die Paketliste doch mal luecken sollte.
backends/mint/postinstall.sh nach backends/mint-image/postinstall.sh als
echte Datei verschoben (war Symlink) - noetig, weil backends/mint/ in
Phase 4 komplett entfernt wird.
Live verifiziert in der enterprise-QEMU-VM: installer.sh von Hand
gestartet, Module 00/05/10/12/15/17 liefen sauber durch, inkl. echtem
Server-Kontakt zu anode und echter Geraeteregistrierung (Liebherr-Org),
Commit-Gate erschien interaktiv wie erwartet, kontrollierter Abbruch ohne
jede destruktive Aktion.
lb config für Debian trixie/amd64, iso-hybrid, GRUB-EFI+syslinux. Paketliste
(tuxflotte.list.chroot) übernimmt die Hardware-/WLAN-Abdeckung aus
build_golden_image.sh, ergänzt um btrfs-progs sowie die bisher erst zur
Laufzeit nachinstallierten Werkzeuge (jq, gettext-base, dosfstools,
e2fsprogs, zstd).
Ersetzt langfristig das Patchen der echten Mint-Live-ISO
(build_customer_iso.sh + Casper-Hook-Injection) - siehe Plan
~/.claude/plans/inherited-floating-treasure.md und Memory
project_independent_boot_medium.md. Auslöser: ein live gefundener Bug, bei
dem statt der direkten Partitionier-Mechanik unerwartet Ubiquity hochkam,
weil das Boot-Medium bislang weiterhin die echte, Ubiquity-tragende
Mint-ISO war.
Noch kein lauffähiges Image - nur das live-build-Grundgerüst, Bau + Boot-
Test folgt.
Zeigt jetzt auf das aus der Proxmox-Referenz-VM golden-linux-mint
gezogene, bereinigte Archiv (linux-mint-22.3-cinnamon.tar.zst,
2,3 GiB komprimiert), gehostet ueber die neue /golden-images/-Route in
provisioning-server. Live per Public-HTTPS verifiziert (voller
Download, byte-exakte Groesse, Traversal/fehlende Datei korrekt
abgelehnt).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
--exclude=/proc (mit fuehrendem Slash) matcht nicht gegen die von
'tar -C / .' erzeugten relativen Elementnamen (./proc/...). Live gegen
die echte Referenz-VM entdeckt: der erste Packlauf haette dadurch
/proc, /sys, /dev, /run, /tmp, /var/tmp real mit eingepackt (u.a.
/proc/kcore) statt sie auszuschliessen. Abgebrochen, Excludes auf
relative Pfade (proc, sys, dev, run, tmp, var/tmp) umgestellt und
lokal mit einem Testverzeichnis verifiziert (inkl. Gegenprobe: ein
'runner/'-Verzeichnis bleibt vom 'run'-Exclude unberuehrt).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ersetzt debootstrap als Hauptweg (siehe ADR-0024-Nachtrag): laeuft direkt
auf einer fertig installierten Referenz-VM (Proxmox), bereinigt
maschinen-/betriebsspezifische Spuren (Testkonto, SSH-Autorisierung,
Root-Passwort, machine-id, SSH-Hostkeys, NetworkManager-Profile,
Caches/Logs) und packt den Dateibaum im selben tar/zstd-Format, das
image_deploy_extract_image() (Phase 1) bereits erwartet.
build_golden_image.sh (debootstrap) bleibt als dokumentierter Fallback
erhalten.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implementiert die von 40_backend.sh erwartete Fuenf-Funktionen-
Lebenszyklus-Schnittstelle (backend_init/validate/generate_config/
launch/postinstall) auf Basis der in Phase 1 isoliert verifizierten
Mechanik in scripts/lib/image_deploy.sh (siehe ADR-0024).
- backend_generate_config() liest dieselben Werte wie das bestehende
Mint-Backend (Hostname, Device-ID, Device-Fingerprint, Root-Dateisystem,
Blueprints-JSON), schreibt sie aber als konsolidierte JSON-Datei statt
eines Preseed/Kickstart-Templates.
- backend_launch() laedt das Golden Image von anode, partitioniert,
formatiert, entpackt, schreibt fstab, macht chroot-Fixup, installiert
den Bootloader.
- backend_postinstall() rendert dasselbe postinstall.sh (per Symlink
geteilt mit backends/mint/, unveraendert wiederverwendet) per envsubst,
fuehrt es per chroot aus, haengt aus, startet neu.
- backend_validate() beschraenkt sich bewusst auf das einfache
Partitionierungsschema ('single') - 'custom' mit extra_partitions ist
noch nicht auf die parted-basierte Mechanik uebertragen, klarer Fehler
statt stiller Fehlinterpretation.
backends/mint/ bleibt unveraendert als Referenz erhalten - neuer,
eigenstaendiger backend_id ('mint-image'), nichts wird live umgeschaltet.
Noch offen (Phase 3): Golden Image muss noch auf anode bereitgestellt
werden (GOLDEN_IMAGE_URL zeigt bereits dorthin), End-to-End-Test ueber
den echten Self-Service-Flow steht noch aus.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
trixie statt bookworm: bookworm ist inzwischen oldstable, trixie liefert
ausserdem von Haus aus einen neueren Kernel - direkt relevant fuers Ziel
'moeglichst breite Hardwareunterstuetzung'. Secure-Boot-Kette
(shim-signed/grub-efi-amd64-signed) funktioniert in beiden Suiten
identisch, kein Unterschied dort.
WLAN-Paketliste erweitert: firmware-brcm80211 (Broadcom, vorher nicht
abgedeckt), wireless-regdb (Regulatory-Datenbank - ohne sie
Kanal-/Sendeleistungs-Einschraenkungen, leicht zu uebersehen),
wpasupplicant explizit (kam vorher nur transitiv mit), iw + rfkill
(Diagnose/Kontrolle).
Noch nicht neu gebaut/getestet - naechster Schritt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real beim Testen entdeckt: mktemp -d legt WORK_DIR mit Modus 0700 an -
debootstrap aendert die Rechte des Zielverzeichnisses selbst nicht, tar -p
uebernimmt diesen Modus beim Verpacken/Entpacken 1:1 als Root-Verzeichnis-
Rechte des gesamten ausgerollten Dateisystems. Ergebnis auf der realen
QEMU-Testplatte: dbus-daemon (wechselt intern auf den unprivilegierten
'messagebus'-Benutzer) bekam 'Permission denied' schon beim Traversieren
von '/', was in einer kompletten Boot-Fehlerkaskade endete (dbus, logind,
NetworkManager, wpa_supplicant, ModemManager schlugen alle fehl - kein
Netzwerk, das eigentliche Ziel von Phase 1). Fix: chmod 0755 direkt nach
debootstrap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real beim Testen entdeckt: grub-install konnte im Testkontext keinen
NVRAM-Booteintrag setzen ('EFI variables are not supported on this
system'), ohne --removable blieb dann nur der benannte
/EFI/tuxflotte/-Pfad uebrig, den die Firmware ohne NVRAM-Eintrag nie
findet - Ergebnis: 'No bootable option or device was found' beim
Testboot von der frisch beschriebenen Platte. Fix: zusaetzlicher
grub-install-Lauf mit --removable schreibt auf den Standard-Fallback-Pfad
EFI/BOOT/BOOTX64.EFI, den jede UEFI-Firmware ohne NVRAM-Eintrag
automatisch versucht - robuster generell fuer heterogene Zielhardware,
nicht nur fuer dieses Testszenario.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue Richtung nach ADR-0024-Diskussion: statt Distributions-Installer
(Ubiquity/Anaconda) zu automatisieren - strukturell fragil, siehe
ADR-0023-Nachtrag zum partman-rebuild-cache-Loop - wird das
curtin/FAI-Muster genutzt: Zieldatentraeger direkt partitionieren, ein
fertiges Root-Filesystem-Image entpacken, per chroot nacharbeiten.
- build_golden_image.sh: baut eine schlanke Debian-bookworm-Basis per
debootstrap (Kernel, breites linux-firmware, NetworkManager,
openssh-server) - KEINE Desktop-Umgebung, die kommt wie jedes andere
Merkmal per Ansible-Blueprint nach dem ersten Boot (ADR-0002). Keine
SSH-Hostkeys/kein Root-Passwort im Ergebnis - reale Zugangsdaten
entstehen erst durch den Provisioning Agent pro Geraet.
- scripts/lib/image_deploy.sh: Kernmechanik als wiederverwendbare
Funktionsbibliothek (partitionieren, formatieren, mounten, Image
entpacken, fstab aus echten UUIDs, chroot-Fixup fuer machine-id/SSH-
Hostkeys/initramfs, Bootloader-Installation UEFI+BIOS).
- scripts/image_deploy_test.sh: isolierter Testtreiber fuer Phase 1,
ruft dieselben Funktionen auf, die spaeter backends/mint-image/
backend.sh (Phase 2) nutzen wird.
Golden Image real gebaut und verifiziert (enterprise/LMDE 6, debootstrap
bookworm): 302 MB, Kernel vorhanden, keine SSH-Hostkeys, machine-id leer.
Deployment-Mechanik noch nicht live getestet - naechster Schritt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Der 'wird ueberprueft'-Text wurde trotz sichtbar auf dem Screenshot nie
gefunden - GtkLabel exponiert seinen Text ueblicherweise nicht ueber
.name/.description (bleiben oft leer), sondern nur ueber das separate
Text-Interface (queryText().getText(0, -1)). _node_text() sammelt jetzt
alle drei Quellen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Timing-Hypothese fuer den partman-rebuild-cache-Loop: der $bootable{}-Fix
brachte live keine Aenderung (siehe ADR-0023-Nachtrag), was gegen einen
rein rezeptseitigen Fehler spricht. Stattdessen zeigt die 'Etwas
Anderes'-Seite waehrend der Klickphase ein Status-Panel 'Konfiguration
der Installation wird ueberprueft ...' - ein Klick auf 'Jetzt
installieren' WAEHREND dieser Pruefung noch laeuft koennte sie
unterbrechen/neu anstossen statt sie abschliessen zu lassen.
atspi_click.py sucht jetzt vor jedem Klickversuch aktiv nach diesem
sichtbaren Text (find_showing_text(), rollenunabhaengig) und gibt bei
Treffer Exit-Code 3 zurueck, ohne zu klicken. autoclicker.sh behandelt
das als eigenen, nicht als Fehlversuch gezaehlten Zustand.
Noch nicht live verifiziert - naechster Schritt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real beim Testen entdeckt: nach einem nachweislich korrekten Klick auf
'Jetzt installieren' (Debug-Log erreichte sogar 'grub-installer/bootdev
seen') sprang der Installer immer wieder zurueck auf dieselbe
Partitionierungsseite - ausgeloest durch die wiederholt gestellte
Debconf-Frage 'ubiquity/partman-rebuild-cache'
(/lib/partman/update.d/99signal_ubiquity), die ubi-partman.py's
rebuild_cache() aufruft.
Vergleich mit der Original-Recipe, aus der unsere ESP-Stanza kopiert
wurde (/usr/lib/partman/recipes-amd64-efi/30atomic): dort traegt NUR die
ESP-Stanza die Boot-Kennzeichnung (method{ efi }), die Root-Partition
bekommt kein zusaetzliches $bootable{ }. Unser Rezept setzte
$bootable{ } bisher unbedingt auf Root, unabhaengig von EFI/BIOS -
moeglicherweise die Ursache der wiederholten Neubewertung durch partman.
Root_extra_flags jetzt bedingt: nur im BIOS-Zweig (wo keine ESP existiert,
die diese Rolle uebernehmen koennte) weiterhin $bootable{ } gesetzt.
Noch nicht live verifiziert - naechster Schritt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real beim Testen entdeckt: ohne diese beiden Parameter (im Gegensatz zum
ersten Boot, dessen grub.cfg-Eintrag sie explizit setzt) verlangt der
Konsolenlogin auf dem zweiten (kexec-)Boot ein echtes, unbekanntes
Passwort statt des sonst leeren Live-Session-Passworts - erschwerte die
Fehlersuche via tty2-Konsole unnoetig. Fuer den GTK-Assistenten selbst
(kein Konsolenlogin noetig) folgenlos, aber Konsistenz zwischen beiden
Boots ist fuer kuenftige Diagnosen wertvoll.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SOURCE_ISO.sha256 (Fedora-Testrest) und der lokale pyc-Cache aus dem
letzten Commit landeten versehentlich per 'git add -A' im Repo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real beim Testen entdeckt: die Mint-eigene 'Multimedia-Codecs'-Seite zeigt
trotz debian-installer/language=de englische Buttons ('Quit'/'Back'/
'Continue') - vermutlich derselbe fehlende .mo-Uebersetzungskatalog wie
beim bereits gepatchten ubi-prepare.py-None-Bug. Die deutsche
FORWARD_LABELS-Werteliste haette hier fuer immer haengen bleiben.
Neue Strategie in select_target(): bekannte rueckwaerts-/abbrechende
Beschriftungen (zweisprachig) werden ausgeschlossen, danach wird bevorzugt
wer eine bekannte vorwaerts-Beschriftung traegt, sonst der einzige
verbleibende Kandidat (Sole-Survivor) - deckt auch unbekannte/nicht
uebersetzte Labels ab. Bei echter Mehrdeutigkeit (mehrere unbekannte
Kandidaten gleichzeitig) wird bewusst NICHT geklickt statt zu raten.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
xdotool/Enter-Taste-Ansatz war nicht zuverlaessig genug (Metacity erzeugt
mehrere ueberlappende X11-Fenster aehnlicher Groesse, 'groesstes Fenster'-
Heuristik traf wiederholt das falsche; Enter aktiviert auf der
Partitionierungs-Uebersicht einen Ausklapp-Pfeil statt 'Jetzt
installieren' - siehe ADR-0023-Nachtrag).
- live-updates/usr/share/ubiquity/tuxflotte-atspi-env.sh (neu): aktiviert
GTK_MODULES=gail:atk-bridge + Session-/A11y-Bus VOR dem GTK-Start von
Ubiquity - muss vor dem Init passieren, eine Bruecke wird von einer
bereits laufenden GTK-App nicht nachgeladen.
- initrd-hooks/casper-bottom/99casperboot: bindet obige Datei per
Ein-Zeilen-Sed-Patch in start-ubiquity-dm ein (dry-run gegen den echten
Datei-Inhalt verifiziert).
- live-updates/opt/tuxflotte/scripts/atspi_click.py (neu): findet+klickt
den passenden 'Weiter'-Button ueber Rolle+Name im Accessibility-Baum,
feste deutsche Werteliste (Sprache per Preseed fest de_DE), niemals
Zurueck/Abbrechen/Beenden.
- autoclicker.sh: ruft atspi_click.py in Schleife statt xdotool/Enter auf,
wartet auf den ubiquity-Prozess statt auf den X-Socket.
Noch nicht live verifiziert - naechster Schritt: QEMU-Testlauf auf lenny.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- noninteractive-Frontend endgueltig verworfen: PageNoninteractive-Stubs
fuehren strukturell zur Endlosschleife im choose_partition-Zustands-
automaten von ubi-partman.py, unabhaengig vom Preseed-Stand.
- Umstieg auf automatic-ubiquity (echte GTK-Oberflaeche) + eigener
Autoklicker (live-updates/opt/tuxflotte/scripts/autoclicker.sh +
systemd-Service), ausgeloest per Boot-Keyword tuxflotte-autoclick.
- Bug 1: jq fehlte beim echten Kiosk-Auslauf (kein manueller Vorab-
Installationsschritt wie in Testlaeufen) - neues Modul
00_preflight.sh installiert es als allererstes.
- Bug 2: echter Ubiquity-Crash in ubi-prepare.py (TypeError: Argument 1
does not allow None as a value) - gezielter Sed-Patch im bestehenden
99casperboot-Hook.
- Bug 3: 'd-i partman/choose_partition select finish' zwang denselben
Endlosschleifen-Zustandsautomaten wie bei noninteractive, auch im
GTK-Modus - Zeile ersatzlos entfernt, partman-auto/method+recipe
genuegen.
- autoclicker.sh: Fenstersuche nach 'ubiquity' korrigiert (Fenstertitel
ist tatsaechlich 'Installation (as superuser)', enthaelt das Wort nie).
- Alle vier Fixes live per QEMU verifiziert (jeweils frische Disk, realer
Kiosk-Ausloeser/kexec-Pfad, nicht nur manuelle Nachstellung).
Offen: automatisierter Klick auf 'Jetzt installieren' auf der
Partitionierungs-Uebersichtsseite noch nicht zuverlaessig (Enter trifft
dort einen Ausklapp-Pfeil statt den Button). Siehe ADR-0023-Nachtrag.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Zwei unabhängige, live in der QEMU-Test-VM gefundene und verifizierte
Bugs, die zusammen jede automatisierte Installation verhindert haben:
1. start-kiosk.sh hatte /home/liveuser hartkodiert (mkdir + Epiphany-
Profilpfad). Der tatsächliche Live-Benutzername auf dieser ISO ist
'mint' (siehe grub/mint-*.cfg, username=mint überall) - /home/liveuser
existiert nie und ist für den Live-User nicht anlegbar. Mit
'set -euo pipefail' brach das Skript an dieser Stelle sofort ab,
TUXFLOTTE_AUTO_MODE wurde nie erreicht, installer.sh lief nie los.
Fix: $HOME statt hartkodiertem Pfad. Passend dazu die sudoers.d/
90-tuxflotte-Regel von 'liveuser' auf 'mint' korrigiert (war zwar
nicht der eigentliche Blocker, da Casper dem Live-User ohnehin
bereits passwortloses sudo gibt, aber inhaltlich falsch/irreführend).
2. backend_launch()s kexec-Sprung nutzte 'automatic-ubiquity' allein -
das startet weiterhin Ubiquitys GTK-Oberfläche (ubiquity-dm), die
Werte aus dem Preseed zwar vorbelegt, aber pro Seite trotzdem auf
einen Klick wartet (live verifiziert: Multimedia-Codecs-Seite blieb
ohne Klick >60s unverändert stehen). Das erklärt die auf echter
Hardware beobachteten "automatischen" Installationen, die dennoch
jede Seite einzeln abfragten. Fix: zusätzliches Boot-Keyword
'noninteractive' (siehe /usr/share/ubiquity/start-ubiquity-dm) lässt
Casper stattdessen 'ubiquity noninteractive' direkt aufrufen -
Ubiquitys eigenes, mitgeliefertes Headless-Frontend
(frontend/noninteractive.py), das jede Seite mit auto_process=True
rein über Debconf abarbeitet, ohne je ein Fenster zu zeichnen.
Live-verifiziert (QEMU, frische Disk): zweiter Boot nach kexec hat
'noninteractive' korrekt im Kernel-Cmdline, ps aux zeigt keinen
GTK-ubiquity-dm-Prozess mehr. /var/log/installer/debug bestätigt den
Frontend-Wechsel eindeutig per Exception-Traceback
(ubiquity.frontend.noninteractive.Wizard.question_dialog wirft
absichtlich NotImplementedError statt zu warten) - zugleich der
nächste, noch offene Befund: ubi-partman.py (Zeile 3484) stellt eine
Frage, die im aktuellen Preseed noch nicht beantwortet ist. Das ist
die einzige verbleibende Lücke zur echten Stille, siehe ADR-0023-
Nachtrag und project_e2e_flow_dogfooding_2026-08-28 (Memory).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Siehe ADR-0023 (platform-docs) fuer die volle Fehlersuche. automatic-
ubiquity+noprompt allein reicht nicht, um jede Ubiquity-Seite zu
unterdruecken (live gefunden: Zeitzone/Codecs/Ueberschreiben/Benutzer-
anlage kamen trotz vollstaendigem Preseed interaktiv). priority=critical
ergaenzt, nur beim Tuxflotte-Auto-Install-Menuepunkt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Siehe ADR-0022 (platform-docs). Beide Backends lesen den bereits waehrend
des Live-Boots berechneten Fingerprint aus hardware.json und schreiben ihn
nach /etc/tuxflotte/device_fingerprint - ermoeglicht beidseitige
Identifikation (Geraeteliste <-> Geraet selbst), vorher nur einseitig
moeglich.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sechster, optionaler Parameter (volid) - provisioning-server berechnet ihn
jetzt aus Organisationsname + Bau-Datum (siehe compute_iso_volid() in
app.py) und reicht ihn durch. Fallback 'TUXFLOTTE' fuer Aufrufe ohne
sechsten Parameter (z.B. manuelle Tests). Keine Aenderung an den
GRUB-/isolinux-Boot-Configs noetig - iso-scan/filename=${iso_path} bzw.
boot=casper referenzieren die Volume-ID nicht direkt, anders als ein
frueherer Notiz-Stand vermuten liess.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mint-boot-grub.cfg: der nicht-EFI-Zweig ('grub_platform != efi') hatte
keinen 'lokale Festplatte booten'-Eintrag und defaultete via 'set
default="0"' auf den ersten Menüeintrag (normaler Live-Boot). Vermutlich
unerreichbar (BIOS läuft laut scripts/build.sh über isolinux, nicht über
diese grub.cfg), aber sicherer, den Zweig genauso abzusichern wie den
EFI-Zweig statt sich auf die Nichterreichbarkeit zu verlassen.
EFI-BOOT-grub.cfg + boot-grub2-grub.cfg (Fedora): echter, nicht nur
theoretischer Fund - 'set default="0"' zeigte dort direkt auf
'Tuxflotte Provisioning (automatisch)', den unbeaufsichtigten
Install-Eintrag. Exakt die unsichere Standardauswahl, die für Mint
bereits am 01.08.2026 korrigiert wurde (siehe ADR-0009), hier aber nie
nachgezogen - das Fedora-Backend bleibt laut ADR-0009 bewusst im Code
für eine mögliche künftige Wiederaufnahme, diese Dateien wären also im
Ernstfall tatsächlich die verwendeten Configs. Jetzt defaulten beide auf
den jeweiligen 'lokal booten'-Eintrag, wie bei Mint.
Alle vier Dateien mit grub2-script-check syntaktisch verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Casper merged /updates nie automatisch auf das gebootete Live-System -
eine seit Projektbeginn unverifizierte Annahme, die erst beim echten
QEMU-Boot (UEFI, kompletter GRUB->Live-Desktop-Pfad) einer personalisierten
Kunden-ISO aufgefallen ist: /opt/tuxflotte fehlte trotz korrekt auf dem
Medium liegendem /cdrom/updates vollständig.
Fix per casper-bottom-Hook, eingebettet via Initrd-Cpio-Konkatenation
(scripts/lib/initrd.sh, derselbe in Phase 1 verifizierte Mechanismus wie
beim Kexec-Preseed). Wichtig dabei: ein komplett neuer Hook-Skriptname wird
nie ausgeführt, weil mkinitramfs eine statische ORDER-Datei mit der
Aufrufliste ins Initrd backt - stattdessen wird der Inhalt des bereits
gelisteten, garantiert letzten Skripts (99casperboot) überschrieben.
start-kiosk.sh erkennt jetzt TUXFLOTTE_AUTO_MODE und startet den Installer
automatisch statt der Kiosk-Startseite. build_customer_iso.sh baut daraus
personalisierte Kunden-ISOs (WLAN-Zugangsdaten + Enrollment-Session-Code).
Nebenbei zwei vorbestehende Bugs behoben: xorriso -osirrox übernimmt
Original-ISO-Dateirechte (oft 444/555, kein Write-Bit), was cp/rm -rf in
build.sh/build_customer_iso.sh bisher unbemerkt kaputt gemacht hat.
Real per QEMU verifiziert (echter GRUB-Boot einer gebauten Kunden-ISO).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auto-Modus (TUXFLOTTE_AUTO_MODE=true, über config/installer.conf als
exportierte Env-Var vor 05_network.sh gesetzt) überspringt alle drei
interaktiven Gates, die bei genauerem Hinsehen existierten (nicht nur
das eine ursprünglich im Plan genannte):
- 05_network.sh: nicht-interaktiver WLAN-Pfad über TUXFLOTTE_WIFI_SSID/
TUXFLOTTE_WIFI_PSK, analog zum bestehenden TUXFLOTTE_ACTIVATION_CODE-
Muster in 12_enrollment_auth.sh (unverändert, unterstützte das schon).
- 17_device_status.sh: "Provisionierung fortsetzen?"-Prompt übersprungen.
- 20_profile_selection.sh: "Vorlage auswählen?"-Prompt übersprungen,
wählt automatisch die als is_default markierte Vorlage (echter
Server-Hinweis via Enrollment Session erst mit Phase 3 möglich).
- 25_installation_confirm.sh: eigentliches Commit-Gate übersprungen.
Alle drei Auto-Modus-Zweige lokal verifiziert (Skripte direkt mit
TUXFLOTTE_AUTO_MODE=true und präparierten Eingabedateien ausgeführt,
kein Hängenbleiben an read -p, korrekte state.env/template.json-Ausgabe).
Partitionierung: installation_directives.partitioning von einfachem
String auf strukturiertes Objekt umgestellt ({"scheme": "single"|
"custom", "root_filesystem", "extra_partitions": [{"mountpoint",
"filesystem", "percent"}]}) - Vertrag, an den sich provisioning-server
in Phase 3 halten muss. backend_generate_config() baut daraus ein
partman-auto/expert_recipe (ersetzt die bisherige choose_recipe-
Fallunterscheidung mit nur "default"/"atomic"), Prozentangaben werden
anhand der realen Zieldatenträgergröße (lsblk/blockdev, erst live auf
dem Zielgerät bekannt) in feste MB-Größen umgerechnet.
Auf UEFI-Systemen wird zusätzlich eine EFI-System-Partition ins Recipe
aufgenommen (sonst verweigert/warnt der Installer, "No EFI System
Partition was found") - exakte Stanza-Syntax nicht aus der Erinnerung
geraten, sondern aus /usr/lib/partman/recipes-amd64-efi/30atomic auf
dem echten Live-Medium ausgelesen ($reusemethod{ } war der fehlende
Teil in einem ersten, geparsten aber nicht erkannten Versuch).
backend_init() installiert jetzt auch jq/envsubst(gettext-base)/cpio
bei Bedarf nach (vorbestehende Lücke neben dem schon in Phase 1
behobenen kexec-tools).
Real per QEMU verifiziert: eigene Ein-Datenträger-Erkennung musste
gehärtet werden (nbd/zram-Geräte mit Größe 0 wurden fälschlich vor dem
echten Datenträger gewählt - auf einer sauberen VM allein wäre das nicht
aufgefallen). Custom-Recipe mit ext4-Root + ext4-/home (20%) +
btrfs-/var (10%) auf 40GB-Testplatte: vollständige unbeaufsichtigte
Installation inkl. Paketinstallation durchlaufen lassen, danach von der
Festplatte (nicht der Live-CD) gebootet - Login-Bildschirm mit korrektem
Hostname erscheint, System bootet einwandfrei per UEFI/ESP.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Startet die unbeaufsichtigte Ubiquity-Installation direkt aus dem
laufenden Live-System heraus per kexec - das personalisierte, erst
zur Laufzeit erzeugte Preseed (Hostname/Geräte-ID/Partitionierung
sind erst hier bekannt) wird dafür in eine zusätzliche Initrd-Schicht
eingebettet (aneinandergehängte cpio-Archive, vom Kernel nativ
unterstützt) statt per file=/cdrom/... (read-only Medium) oder
url=<lokaler Server> (Prozess-/Netzwerkzustand geht beim Kexec-Sprung
verloren).
backend_init() installiert kexec-tools jetzt bei Bedarf nach (auf dem
Live-Medium anders als im Zielsystem nicht vorinstalliert).
Real per QEMU verifiziert: kexec aus laufender Live-Sitzung heraus
funktioniert, automatic-ubiquity mit sowohl url= als auch
initrd-eingebettetem file= erreicht, komplette unbeaufsichtigte
Installation (Partitionierung, Paketinstallation, success_command)
bis zum funktionierenden Login-Bildschirm durchlaufen lassen. Danach
zusätzlich der tatsächliche, committete backend.sh-Code (nicht nur
die Spike-Annäherung) end-to-end über alle fünf Lifecycle-Funktionen
gegen ein reales runtime_blueprint.json/response.json bestätigt.
Bekannte Restlücke: jq/envsubst/base64 sind auf dem Live-Medium
ebenfalls nicht vorinstalliert (backend_init prüft nur, installiert
nicht nach) - vorbestehende Lücke, nicht Teil dieser Änderung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fehlte bisher komplett - backends/mint/ enthielt nur handgepatchte
WLAN-Test-Artefakte, kein backend.sh, sodass 40_backend.sh mit
"Kein Backend für 'mint' gefunden" abbrach.
Baut auf dem bereits real erprobten wlan-test.seed-Muster auf (Ubiquity/
Preseed, nicht Subiquity/Autoinstall - siehe ADR-0009), generalisiert zu
einem echten Template mit denselben Platzhaltern wie Fedoras kickstart.tpl:
- backends/mint/backend.sh: 5-Funktionen-Contract 1:1 wie Fedora
(backend_init/validate/generate_config/launch/postinstall),
backend_launch() bewusst als Stub (echte Parität mit Fedoras
heutigem Stand, kein Vorgriff auf das noch nicht entschiedene
Self-Service-Portal-Modell).
- backends/mint/preseed.tpl + postinstall.sh: echter Agent-Bootstrap
(curl agent.py, Bootstrap-POST, Credentials, systemd enable) im
ubiquity/success_command, zweistufig envsubst+base64 gerendert
(Debconf-Fallstrick bei mehrzeiligen Preseed-Werten, real erprobt).
- scripts/build.sh: Backend-Argument (fedora|mint), Mint-Pfade real
gegen die vorhandene Test-ISO verifiziert (/boot/grub/grub.cfg,
/isolinux/live.cfg, /preseed/tuxflotte.seed - keine zweite ESP-Kopie
wie bei Fedora), Test-Preseed-Bake mit Platzhalterwerten.
- profiles/mint-desktop/profile.json: installer.type von "autoinstall"
auf "preseed" korrigiert (ADR-0009 hatte den alten Wert als vermutlich
falsch benannt markiert - jetzt bestätigt und korrigiert).
End-to-end auf echter QEMU-Hardware verifiziert: automatisierte
Installation, Reboot, Agent-Bootstrap, Check-in, ansible-pull-Zyklus
(PLAY RECAP failed=0) - kompletter Kreislauf funktioniert. Dabei
gefunden und gefixt: d-i pkgsel/include string ansible-core git fehlte
(Pendant zu Fedoras kickstart.tpl %packages) - ohne das lief der
Agent-Dienst in einer Restart-Fehlerschleife.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fetch the provisioning agent from git.tuxflotte.de, register it via
POST /api/v1/agent/bootstrap using the device id from the activation
response, write /etc/tuxflotte/agent.credentials, and enable the
tuxflotte-agent systemd service so it starts on first boot. Verified
end to end against a QEMU test VM and the real anode API.
The device id is now threaded through backend_generate_config() and
substituted into the kickstart template like the existing hostname
and blueprint values. %post drops the implicit chroot-wide set -e in
favor of per-step error handling, since localectl calls in this
section are known to fail best-effort without a running D-Bus.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Boot menus now default to "boot from local disk" instead of the
destructive auto-install entry -- the earlier version would have run
the destructive install automatically on a timeout with no action
taken, backwards from the intended safety gate.
early-command-test-FAILED.sh is kept as-is (not wired into the seed)
purely as a record of what was tried: d-i preseed/early_command never
executed at all under Ubiquity, see ADR-0009's 01.08.2026 update for
why (Ubiquity's own Python plugin architecture has no hook for it).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Manual test artifacts (like backends/fedora/*-test.cfg), not part of a
backend lifecycle yet -- Mint has no backend.sh implementation. These
are what actually proved on real hardware that WLAN works during
Ubiquity's install, live contact with anode during install works, and
a directly-written .nmconnection file survives into the installed
system and reconnects automatically.
wlan-test.seed: the deployed preseed (file=/cdrom/preseed/...seed,
automatic-ubiquity). success_command is base64-encoded -- the
human-readable source for that is wlan-test-post-install.sh; a
straightforward multi-line quoted success_command value silently never
ran at all, traced to debconf's own preseed line-continuation
handling, not a bash issue (see ADR-0009's 31.07.2026 updates).
wlan-test-boot-grub.cfg / wlan-test-isolinux-live.cfg: the patched
UEFI/BIOS boot menus, unlike Fedora's ISO this medium has no hidden
second FAT/ESP grub.cfg copy to patch separately.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same offline-install idea as wlan-netinst-test.cfg but on a genuine
DVD/Everything-style medium instead of netinstall, to sidestep the
network dependency during %packages. Ended up hanging at
dracut-initqueue for a reason that turned out to be independent of the
network line entirely (confirmed by testing with no network directive
at all, then with a physical Ethernet cable plugged in) -- see the
30.07.2026 ADR-0009 update for the full account.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Not part of the backend lifecycle (40_backend.sh) -- run by hand during
the live/netinstall boot flow investigation documented in ADR-0009.
kexec-reboot-test.sh/.cfg: tests whether inst.ks= can trigger Anaconda
via kexec from within the running Fedora Cinnamon live session, without
a real firmware reboot. Conclusively fails: the live initrd has no
anaconda dracut module at all.
wlan-netinst-test.cfg: the kickstart used to validate inst.ks=cdrom:/ks.cfg
on a real Fedora netinstall ISO, including the failed WLAN activation
attempts (network --wpakey=, then %pre nmcli) that exposed the missing
iwlwifi driver in that image's initrd.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the gnome-terminal-launched installer.sh session with a
browser-based kiosk (opt/tuxflotte/kiosk/start-kiosk.sh launching
Epiphany with --profile). Sets German keyboard layout for the
graphical session (vconsole.keymap only covers the text console),
suppresses Epiphany's default-browser prompt, hides desktop icons,
and reduces the panel to a window list + power applet. Also disables
the SELinux troubleshooter desktop notification, and copies the full
live-updates tree (not just etc/) so opt/ payload ships too.
Several Epiphany invocation modes were tried and discarded before
landing on plain --profile=<dir> (see ADR-0004/0006 and platform-docs
history for the rejected --application-mode/--private-instance paths).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The GRUB config searched for the volume by the original Fedora label
(Fedora-Cinn-Live-44), which no longer matches once the ISO is built
with its own Tuxflotte volume ID.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uses dracut's official 20-apply-live-updates.sh pre-pivot hook: any
/updates/ directory tree present at the top level of the boot media
gets copied into the live root filesystem before pivoting, verbatim,
no initrd or squashfs/EROFS modification needed. build.sh assembles
this tree from scripts/, backends/, config/ (mapped under
/opt/tuxflotte) plus live-updates/etc/ (an XDG autostart entry that
opens a terminal running installer.sh as root, and a sudoers.d drop-in
granting liveuser passwordless sudo).
xorriso preserves the ownership/permissions recorded at map time, so
-chown_r/-chgrp_r 0 on /updates is enough to make sudoers accept the
drop-in as root-owned without needing local root to build the ISO.
This was tried first as a direct EROFS unpack/repack of
/LiveOS/squashfs.img (that file is actually EROFS despite the name on
current Fedora), but a fresh self-built erofs-utils (Debian's
packaged 1.5-1 can't even read this image's on-disk format) hit a
reproducible bug extracting the packed/fragmented inode into a single
corrupt file instead of a directory tree. The dracut hook sidesteps
that path entirely.
Verified end-to-end: booting either Tuxflotte entry reaches the
Cinnamon live desktop, autostarts a terminal, and installer.sh runs
through every module (network, hardware, enrollment, handshake,
device status, Bereitstellungsvorlage selection, commit point, Runtime
Blueprint resolution against the real server, full Fedora backend
lifecycle, storage detection) to a clean exit.
It called log_info/log_warn/error_exit/list_install_disks without
sourcing anything - leftover from before modules were run as
standalone subprocesses via run_module() rather than sourced into
installer.sh. Never noticed because the pipeline never reached this
module in a live run until now. Behavior unchanged: still just lists
disks and warns that partitioning is disabled (Phase 1).
export_connection_profile() crashed the whole installer under set -e/
pipefail when the active NetworkManager connection has no backing
keyfile (common for ephemeral live-boot DHCP connections) - nmcli
returned a non-zero exit status even though the guard below already
handles an empty result gracefully. Every other nmcli call in this
function already has this || true safety net; this one was missing it.
Found via a live end-to-end boot test in Proxmox.