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>
228 lines
5.7 KiB
Bash
Executable File
228 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SOURCE_ISO="${1:-}"
|
|
BACKEND="${2:-}"
|
|
|
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
BASE_DIR="$(cd "$REPO_DIR/.." && pwd)"
|
|
BUILD_DIR="$BASE_DIR/build"
|
|
WORK_DIR="$BUILD_DIR/work"
|
|
OUTPUT_DIR="$BUILD_DIR/output"
|
|
|
|
# Test-Device fuer den in bake_test_preseed() eingebrannten, nicht
|
|
# personalisierten Test-Preseed (Mint) - dasselbe "Default Lab"-Testgeraet,
|
|
# das schon fuer die Fedora-Verifikation genutzt wurde. Echte Personalisierung
|
|
# pro Kunde ist nicht Teil dieses Build-Skripts (siehe ADR-0011-Kontext).
|
|
TEST_DEVICE_ID="a0238a0b-d2b5-4516-a6ce-da7170041d11"
|
|
TEST_HOSTNAME="tuxflotte-mint-test"
|
|
|
|
usage() {
|
|
echo "Usage: $0 /path/to/source.iso <fedora|mint>"
|
|
}
|
|
|
|
check_input() {
|
|
if [[ -z "$SOURCE_ISO" || -z "$BACKEND" ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$SOURCE_ISO" ]]; then
|
|
echo "Error: ISO not found: $SOURCE_ISO"
|
|
exit 1
|
|
fi
|
|
|
|
case "$BACKEND" in
|
|
fedora|mint) ;;
|
|
*)
|
|
echo "Error: unbekanntes Backend '$BACKEND' (erwartet: fedora oder mint)"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
check_dependencies() {
|
|
for cmd in xorriso; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
echo "Error: missing dependency: $cmd"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if [[ "$BACKEND" == "mint" ]]; then
|
|
for cmd in jq envsubst base64; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
echo "Error: missing dependency: $cmd"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
prepare_dirs() {
|
|
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR"
|
|
rm -rf "$WORK_DIR"
|
|
mkdir -p "$WORK_DIR"
|
|
}
|
|
|
|
extract_iso() {
|
|
echo "Extracting ISO..."
|
|
xorriso -indev "$SOURCE_ISO" -osirrox on -extract / "$WORK_DIR" >/dev/null
|
|
}
|
|
|
|
patch_grub() {
|
|
echo "Installing Tuxflotte GRUB configuration..."
|
|
|
|
if [[ "$BACKEND" == "fedora" ]]; then
|
|
cp "$REPO_DIR/grub/EFI-BOOT-grub.cfg" \
|
|
"$WORK_DIR/EFI/BOOT/grub.cfg"
|
|
|
|
cp "$REPO_DIR/grub/boot-grub2-grub.cfg" \
|
|
"$WORK_DIR/boot/grub2/grub.cfg"
|
|
else
|
|
# Mint hat, anders als Fedora, keine zweite ESP/FAT-Kopie des GRUB-Menüs,
|
|
# die separat gepatcht werden müsste (real gegen die vorhandene
|
|
# tuxflotte-mint-test.iso verifiziert - x86_64-efi/grub.cfg ist nur ein
|
|
# Loader-Stub, der per `source /boot/grub/grub.cfg` zurückverweist).
|
|
cp "$REPO_DIR/grub/mint-boot-grub.cfg" \
|
|
"$WORK_DIR/boot/grub/grub.cfg"
|
|
|
|
cp "$REPO_DIR/grub/mint-isolinux-live.cfg" \
|
|
"$WORK_DIR/isolinux/live.cfg"
|
|
fi
|
|
}
|
|
|
|
verify_workdir() {
|
|
echo "Verifying workdir..."
|
|
|
|
if [[ "$BACKEND" == "fedora" ]]; then
|
|
grep -q "Tuxflotte" "$WORK_DIR/EFI/BOOT/grub.cfg"
|
|
grep -q "Tuxflotte" "$WORK_DIR/boot/grub2/grub.cfg"
|
|
else
|
|
grep -q "Tuxflotte" "$WORK_DIR/boot/grub/grub.cfg"
|
|
grep -q "Tuxflotte" "$WORK_DIR/isolinux/live.cfg"
|
|
fi
|
|
|
|
echo "GRUB verification passed."
|
|
}
|
|
|
|
bake_test_preseed() {
|
|
[[ "$BACKEND" == "mint" ]] || return 0
|
|
|
|
echo "Rendering test preseed (nicht personalisiert, siehe TEST_DEVICE_ID)..."
|
|
|
|
local preseed_dir="$WORK_DIR/preseed"
|
|
local runtime_blueprint_file="$WORK_DIR/runtime_blueprint.json"
|
|
local server_response_file="$WORK_DIR/response.json"
|
|
|
|
mkdir -p "$preseed_dir"
|
|
|
|
cat > "$runtime_blueprint_file" <<EOF
|
|
{
|
|
"runtime_blueprint": {
|
|
"backend_id": "mint",
|
|
"blueprints": [],
|
|
"installation_directives": {
|
|
"disk_encryption": false,
|
|
"partitioning": {"scheme": "single", "root_filesystem": "ext4"},
|
|
"secure_boot_required": false
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
|
|
cat > "$server_response_file" <<EOF
|
|
{
|
|
"device": {"hostname": "${TEST_HOSTNAME}", "id": "${TEST_DEVICE_ID}"}
|
|
}
|
|
EOF
|
|
|
|
# backend.sh direkt wiederverwenden statt die Templating-Logik hier zu
|
|
# duplizieren - Variablen sind bewusst nicht readonly (siehe backend.sh),
|
|
# backend_init() wird übersprungen (braucht root für --owner/--group,
|
|
# hier nicht nötig, mkdir reicht für den Build-Kontext).
|
|
# shellcheck disable=SC1091
|
|
source "$REPO_DIR/backends/mint/backend.sh"
|
|
|
|
RUNTIME_BLUEPRINT_FILE="$runtime_blueprint_file"
|
|
SERVER_RESPONSE_FILE="$server_response_file"
|
|
RUNTIME_DIR="$preseed_dir"
|
|
CONFIG_FILE="$preseed_dir/tuxflotte.seed"
|
|
|
|
backend_validate
|
|
backend_generate_config
|
|
|
|
echo "Test-Preseed erzeugt: $CONFIG_FILE"
|
|
}
|
|
|
|
prepare_updates() {
|
|
echo "Assembling live-updates payload..."
|
|
|
|
local updates_dir="$WORK_DIR/updates"
|
|
|
|
rm -rf "$updates_dir"
|
|
mkdir -p "$updates_dir/opt/tuxflotte"
|
|
|
|
cp -a "$REPO_DIR/live-updates/." "$updates_dir/"
|
|
cp -a "$REPO_DIR/scripts" "$updates_dir/opt/tuxflotte/"
|
|
cp -a "$REPO_DIR/backends" "$updates_dir/opt/tuxflotte/"
|
|
cp -a "$REPO_DIR/config" "$updates_dir/opt/tuxflotte/"
|
|
|
|
chmod 0440 "$updates_dir/etc/sudoers.d/90-tuxflotte"
|
|
}
|
|
|
|
create_iso() {
|
|
echo "Creating Tuxflotte ISO..."
|
|
|
|
local output_iso
|
|
local -a grub_map_args
|
|
|
|
if [[ "$BACKEND" == "fedora" ]]; then
|
|
output_iso="$OUTPUT_DIR/tuxflotte-provisioning-0.2.iso"
|
|
grub_map_args=(
|
|
-map "$REPO_DIR/grub/EFI-BOOT-grub.cfg" /EFI/BOOT/grub.cfg
|
|
-map "$REPO_DIR/grub/boot-grub2-grub.cfg" /boot/grub2/grub.cfg
|
|
)
|
|
else
|
|
output_iso="$OUTPUT_DIR/tuxflotte-mint-provisioning-0.1.iso"
|
|
grub_map_args=(
|
|
-map "$REPO_DIR/grub/mint-boot-grub.cfg" /boot/grub/grub.cfg
|
|
-map "$REPO_DIR/grub/mint-isolinux-live.cfg" /isolinux/live.cfg
|
|
-map "$WORK_DIR/preseed/tuxflotte.seed" /preseed/tuxflotte.seed
|
|
)
|
|
fi
|
|
|
|
rm -f "$output_iso"
|
|
|
|
xorriso \
|
|
-indev "$SOURCE_ISO" \
|
|
-outdev "$output_iso" \
|
|
-compliance no_emul_toc \
|
|
-volid TUXFLOTTE \
|
|
"${grub_map_args[@]}" \
|
|
-map "$WORK_DIR/updates" /updates \
|
|
-chown_r 0 /updates -- \
|
|
-chgrp_r 0 /updates -- \
|
|
-boot_image any replay
|
|
|
|
echo "ISO created: $output_iso"
|
|
}
|
|
|
|
main() {
|
|
check_input
|
|
check_dependencies
|
|
prepare_dirs
|
|
extract_iso
|
|
patch_grub
|
|
verify_workdir
|
|
bake_test_preseed
|
|
prepare_updates
|
|
create_iso
|
|
|
|
echo
|
|
echo "Build complete."
|
|
echo "Work dir: $WORK_DIR"
|
|
}
|
|
|
|
main "$@"
|