39 Commits

Author SHA1 Message Date
f6bb3db9b9 fix(boot-medium): unsquashfs auf anode - /dev von Extraktion ausschliessen
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.
2026-09-01 09:50:42 +02:00
d179f9c2f5 chore(boot-medium): Phase 4 - alte Ubiquity-Ära-Dateien entfernen, build.sh auf Fedora reduzieren
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).
2026-09-01 09:22:19 +02:00
27d6fa0f47 feat(boot-medium): build_customer_iso.sh ans neue Struktur anpassen (Phase 3) + vier echte Deployment-Bugs behoben
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.
2026-08-31 16:36:35 +02:00
95447f7486 feat(boot-medium): Begrüßungsbanner (Tuxflotte-Schriftzug + Flottengrafik)
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.
2026-08-31 14:57:09 +02:00
bc13169418 feat(boot-medium): systemd-Autostart, Fortschrittsanzeige, SSH-Dev-Modus (Phase 2)
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.
2026-08-31 14:40:39 +02:00
2190d6f403 feat(boot-medium): Tuxflotte-Nutzlast ins Boot-Medium einbauen (Phase 1)
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.
2026-08-31 13:52:38 +02:00
86ebea6d66 fix(golden-image): tar --exclude braucht relative Pfade bei -C /
--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>
2026-08-31 09:38:09 +02:00
cb182a058f feat: package_golden_image.sh - Golden Image aus einer echten Referenz-VM ziehen
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>
2026-08-31 09:31:03 +02:00
8be6ece0d3 feat: Golden Image auf Debian trixie umstellen, WLAN-Abdeckung erweitern
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>
2026-08-30 18:45:24 +02:00
d35f1d257e fix: zstd -f setzen, damit wiederholte Golden-Image-Baeulaeufe die vorherige Ausgabedatei ueberschreiben
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 23:39:46 +02:00
fec208be5f fix: Root-Dateisystem des Golden Image auf 0755 statt 0700 korrigieren
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>
2026-08-29 23:36:19 +02:00
f57bdea9b1 fix: GRUB zusaetzlich auf EFI-Fallback-Pfad installieren (--removable)
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>
2026-08-29 22:52:22 +02:00
5845e0108a feat: Golden-Image-Deployment als Ersatz fuer Ubiquity-Automatisierung (Phase 0+1)
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>
2026-08-29 22:26:37 +02:00
941a58535d fix: noninteractive verworfen, automatic-ubiquity+Autoklicker, drei echte Bugs behoben
- 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>
2026-08-29 15:16:41 +02:00
d5010f5c7b feat: Volume-ID der Kunden-ISO per Parameter statt fest 'TUXFLOTTE'
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>
2026-08-25 09:04:38 +02:00
683cf70af5 fix: /updates auf dem Live-System deployen + Kunden-ISO-Build (Phase 4)
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>
2026-08-06 22:18:04 +02:00
108444ecf7 feat: Auto-Modus + prozentuale Partitionierung für Mint (Phase 2)
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>
2026-08-06 16:12:56 +02:00
15965551ec feat: Mint-Backend fuer den Installer (backend.sh + preseed.tpl)
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>
2026-08-04 19:00:16 +02:00
50e41e2230 feat: switch kiosk autostart from terminal installer to Epiphany browser kiosk
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>
2026-07-22 12:12:37 +02:00
1e83a27a57 fix: match GRUB search label to the TUXFLOTTE ISO volume ID
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>
2026-07-22 12:12:23 +02:00
cd91a6b393 feat: run installer.sh automatically inside the live session
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.
2026-07-20 14:52:05 +02:00
dd7147aee0 fix: make 20_storage.sh self-contained like every other module
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).
2026-07-20 14:51:28 +02:00
6a48a7c929 fix: tolerate nmcli connection.filename failure for in-memory live connections
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.
2026-07-20 14:51:22 +02:00
1a38f8ef3c fix: set execute bit on Fedora backend and runtime-blueprint/backend modules
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.
2026-07-20 14:51:12 +02:00
804827c5a9 feat: switch provisioning ISO to a live medium with auto/interactive boot entries
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.
2026-07-18 17:08:12 +02:00
086917deec feat: resolve Runtime Blueprint and add Fedora backend for kickstart generation
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).
2026-07-18 10:49:50 +02:00
3a7549adf1 fix: align profile selection and installation confirm with Bereitstellungsvorlage model
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.
2026-07-18 10:49:42 +02:00
f7f8e93c30 feat: prompt for bootstrap enrollment authorization 2026-07-14 13:44:31 +02:00
262fa88057 refactor: isolate enrollment authorization from handshake 2026-07-14 13:39:56 +02:00
b11fa1cb76 feat: add device status interaction and early abort 2026-07-14 13:26:48 +02:00
f1cb04bd24 feat: add interactive provisioning flow and commit point 2026-07-14 12:41:01 +02:00
1d3262d69f feat: integrate network and server handshake into installer flow 2026-07-14 10:57:59 +02:00
57ece79693 feat: add local boot entries and bump ISO to 0.2 2026-07-13 10:46:33 +02:00
0116e4b905 feat: implement provisioning server handshake 2026-07-13 09:25:10 +02:00
dc8a2df9d2 feat: initialize provisioning network 2026-07-13 09:15:37 +02:00
74a6e181ce feat: collect hardware and device identity 2026-07-13 09:15:00 +02:00
b1f35a5ef4 Refactor installer into modular orchestration framework 2026-07-07 10:27:32 +02:00
655da9d431 Add unified installer build script 2026-07-06 14:43:24 +02:00
bdba09b3e1 Add ISO extraction script 2026-07-06 14:30:26 +02:00