tuxflotte-installer/scripts/modules/17_device_status.sh
Thomas Stallinger 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

134 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly SCRIPT_NAME
readonly SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json"
readonly RUNTIME_DIR="/run/tuxflotte/provisioning"
readonly STATE_FILE="${RUNTIME_DIR}/state.env"
log() {
printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" >&2
}
fatal() {
printf '[%s] FEHLER: %s\n' "${SCRIPT_NAME}" "$*" >&2
exit 1
}
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
fatal "Das Gerätestatusmodul muss als root ausgeführt werden."
fi
}
prepare_runtime() {
install -d \
--mode=0700 \
--owner=root \
--group=root \
"${RUNTIME_DIR}"
rm -f -- "${STATE_FILE}"
}
store_provisioning_state() {
local continue_provisioning="$1"
umask 077
printf 'TUXFLOTTE_PROVISIONING_CONTINUE=%s\n' \
"${continue_provisioning}" >"${STATE_FILE}"
chmod 0600 "${STATE_FILE}"
}
validate_server_response() {
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"
jq --exit-status '
.success == true
and (.device | type == "object")
and (.device.registration_status == "existing"
or .device.registration_status == "registered")
and (.customer | type == "object")
' "${SERVER_RESPONSE_FILE}" >/dev/null ||
fatal "Serverantwort enthält keinen gültigen Gerätestatus."
}
show_device_status() {
local registration_status
local hostname
local organization_name
registration_status="$(
jq -r '.device.registration_status' "${SERVER_RESPONSE_FILE}"
)"
hostname="$(
jq -r '.device.hostname // "unbekannt"' "${SERVER_RESPONSE_FILE}"
)"
organization_name="$(
jq -r '.customer.name // "unbekannt"' "${SERVER_RESPONSE_FILE}"
)"
printf '\n'
case "${registration_status}" in
existing)
printf 'Bekanntes Gerät erkannt\n'
printf '========================\n\n'
printf 'Gerät: %s\n' "${hostname}"
printf 'Organisation: %s\n' "${organization_name}"
printf '\n'
printf 'Das Gerät ist bereits registriert.\n'
;;
registered)
printf 'Neues Gerät registriert\n'
printf '=======================\n\n'
printf 'Gerät: %s\n' "${hostname}"
printf 'Organisation: %s\n' "${organization_name}"
printf '\n'
printf 'Hinweis:\n'
printf 'Die Registrierung erfolgte über den temporären Bootstrap-Aktivierungsmechanismus.\n'
;;
esac
}
confirm_provisioning() {
local answer
if [[ "${TUXFLOTTE_AUTO_MODE:-false}" == "true" ]]; then
store_provisioning_state true
log "Auto-Modus: Provisionierung wird ohne Rückfrage fortgesetzt."
return 0
fi
printf '\n'
read -r -p "Provisionierung fortsetzen? [j/N]: " answer
case "${answer}" in
j|J|ja|JA|Ja)
store_provisioning_state true
log "Provisionierung wird fortgesetzt."
;;
*)
store_provisioning_state false
log "Provisionierung wurde durch den Benutzer beendet."
;;
esac
}
main() {
require_root
prepare_runtime
validate_server_response
show_device_status
confirm_provisioning
}
main "$@"