26 Commits

Author SHA1 Message Date
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