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.
These are run as standalone subprocesses via run_module()/source, which
requires the execute bit. Missing since their initial creation - only
noticed because manually chmod'd copies were used for testing on anode,
never the checked-in files. Would have failed on a fresh checkout.
Blue-on-white (matching pics/tuxflotte-beschriftet-schatten.svg's
brand color rgb(52,101,164)) instead of GRUB's default white-on-black.
The logo image itself doesn't work here: classic gfxterm always paints
an opaque per-character cell background, so a background_image gets
fully covered by color_normal's background and never becomes visible -
confirmed by booting the composited variant in QEMU before dropping it
again. Showing the actual logo needs the GRUB theme/gfxmenu engine,
which this live ISO doesn't ship (empty /boot/grub2/themes, no
x86_64-efi module directory) - not attempted here. The logo fits more
naturally on the Plymouth splash or live-desktop wallpaper instead,
both already confirmed to render correctly.
Replaces the Fedora DVD/netinst base with a live-ISO boot chain
(root=live:CDLABEL=Fedora-Cinn-Live-44 rd.live.image instead of
inst.stage2=/inst.ks=), implementing ADR-0003. The GRUB menu now
offers two entries booting the same live image with a
tuxflotte.mode=auto/interactive kernel cmdline flag instead of a
boot-time kickstart URL - installer.sh will read this flag once it
runs inside the live session.
scripts/build.sh and scripts/extract.sh now extract the source ISO via
`xorriso -osirrox` instead of a loop mount, removing the sudo
dependency for local builds.
Verified end-to-end in QEMU/KVM: GRUB menu renders both entries,
kernel/initrd load correctly, boot proceeds to the live session.
30_runtime_blueprint.sh calls POST /templates/{id}/resolve with the
device_id from the server handshake and the template_id from the
Bereitstellungsvorlage selection, storing the resulting Runtime
Blueprint under /run/tuxflotte/runtime/.
40_backend.sh dispatches to backends/${backend_id}/backend.sh based on
the resolved backend_id and drives the backend_init/validate/
generate_config/launch/postinstall lifecycle from 06-backend-api.md.
backends/fedora/backend.sh implements that lifecycle for Fedora:
backend_generate_config() renders kickstart.tpl via envsubst using the
Runtime Blueprint's installation_directives and the device hostname,
embedding the resolved Merkmal blueprints as JSON for the (not yet
implemented) Provisioning Agent to apply later. Replaces the old
git-clone-based %post bootstrap. backend_launch()/backend_postinstall()
are Phase 1 stubs pending the live-ISO boot integration (see
platform-docs ADR-0003).
20_profile_selection.sh and 25_installation_confirm.sh still spoke the
old flat profile model (.profiles[], .profile.distribution,
.profile.installer.type) that the provisioning server no longer
returns - it now returns .templates[] with workspace/backend objects
(see provisioning-server's Merkmal/Blueprint/Bereitstellungsvorlage
migration). Both modules now read/write
/run/tuxflotte/assignment/template.json against the current
Bereitstellungsvorlage schema, matching 10-interactive-provisioning-flow.md.