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>
160 lines
4.3 KiB
Bash
Executable File
160 lines
4.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/assignment"
|
|
readonly TEMPLATE_FILE="${RUNTIME_DIR}/template.json"
|
|
|
|
log() {
|
|
printf '[%s] %s\n' "${SCRIPT_NAME}" "$*"
|
|
}
|
|
|
|
fatal() {
|
|
printf '[%s] FEHLER: %s\n' "${SCRIPT_NAME}" "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_root() {
|
|
if [[ "${EUID}" -ne 0 ]]; then
|
|
fatal "Das Profilauswahlmodul muss als root ausgeführt werden."
|
|
fi
|
|
}
|
|
|
|
prepare_runtime() {
|
|
install -d -m 0700 "${RUNTIME_DIR}"
|
|
rm -f -- "${TEMPLATE_FILE}"
|
|
}
|
|
|
|
validate_server_response() {
|
|
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
|
|
fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"
|
|
|
|
jq --exit-status . "${SERVER_RESPONSE_FILE}" >/dev/null ||
|
|
fatal "Serverantwort enthält kein gültiges JSON."
|
|
|
|
jq --exit-status '
|
|
.success == true
|
|
and (.templates | type == "array")
|
|
and (.templates | length > 0)
|
|
' "${SERVER_RESPONSE_FILE}" >/dev/null ||
|
|
fatal "Serverantwort enthält keine auswählbaren Bereitstellungsvorlagen."
|
|
}
|
|
|
|
show_templates() {
|
|
local index=1
|
|
local template
|
|
|
|
log "Verfügbare Bereitstellungsvorlagen:"
|
|
|
|
while IFS= read -r template; do
|
|
printf '\n'
|
|
printf ' %d) %s' \
|
|
"${index}" \
|
|
"$(jq -r '.label' <<<"${template}")"
|
|
|
|
if [[ "$(jq -r '.is_default' <<<"${template}")" == "true" ]]; then
|
|
printf ' (Standard)'
|
|
fi
|
|
|
|
printf '\n'
|
|
|
|
printf ' Workspace: %s\n' \
|
|
"$(jq -r '.workspace.name' <<<"${template}")"
|
|
|
|
printf ' Backend: %s %s\n' \
|
|
"$(jq -r '.backend.name' <<<"${template}")" \
|
|
"$(jq -r '.backend.version' <<<"${template}")"
|
|
|
|
((index += 1))
|
|
done < <(jq -c '.templates[]' "${SERVER_RESPONSE_FILE}")
|
|
}
|
|
|
|
select_template_auto() {
|
|
local default_index
|
|
|
|
# Kein spezifischer Server-Hinweis vorhanden (Enrollment Sessions legen
|
|
# serverseitig zwar schon eine Bereitstellungsvorlage fest, die
|
|
# Verbrauchslogik dafür existiert aber noch nicht - siehe Phase 3 im
|
|
# Plan) - bis dahin wird im Auto-Modus die als is_default markierte
|
|
# Vorlage gewählt.
|
|
default_index="$(
|
|
jq '[.templates[] | .is_default] | index(true)' "${SERVER_RESPONSE_FILE}"
|
|
)"
|
|
|
|
[[ "${default_index}" != "null" ]] ||
|
|
fatal "Auto-Modus: keine Standard-Bereitstellungsvorlage in der Serverantwort markiert."
|
|
|
|
jq \
|
|
--argjson index "${default_index}" \
|
|
'{
|
|
schema_version: 1,
|
|
template: .templates[$index]
|
|
}' \
|
|
"${SERVER_RESPONSE_FILE}" >"${TEMPLATE_FILE}"
|
|
|
|
log "Auto-Modus: Standard-Bereitstellungsvorlage automatisch gewählt."
|
|
}
|
|
|
|
select_template_interactive() {
|
|
local template_count
|
|
local selection
|
|
|
|
template_count="$(jq '.templates | length' "${SERVER_RESPONSE_FILE}")"
|
|
|
|
while true; do
|
|
printf '\n'
|
|
read -r -p "Bereitstellungsvorlage auswählen [1-${template_count}]: " selection
|
|
|
|
if [[ "${selection}" =~ ^[0-9]+$ ]] &&
|
|
((selection >= 1 && selection <= template_count)); then
|
|
break
|
|
fi
|
|
|
|
log "Ungültige Auswahl."
|
|
done
|
|
|
|
jq \
|
|
--argjson index "$((selection - 1))" \
|
|
'{
|
|
schema_version: 1,
|
|
template: .templates[$index]
|
|
}' \
|
|
"${SERVER_RESPONSE_FILE}" >"${TEMPLATE_FILE}"
|
|
}
|
|
|
|
select_template() {
|
|
if [[ "${TUXFLOTTE_AUTO_MODE:-false}" == "true" ]]; then
|
|
select_template_auto
|
|
else
|
|
select_template_interactive
|
|
fi
|
|
|
|
chmod 0600 "${TEMPLATE_FILE}"
|
|
|
|
jq --exit-status '
|
|
.schema_version == 1
|
|
and (.template | type == "object")
|
|
and (.template.id | type == "string")
|
|
and (.template.id | length > 0)
|
|
and (.template.workspace | type == "object")
|
|
and (.template.backend | type == "object")
|
|
' "${TEMPLATE_FILE}" >/dev/null ||
|
|
fatal "Ausgewählte Bereitstellungsvorlage konnte nicht gültig gespeichert werden."
|
|
|
|
log "Bereitstellungsvorlage $(jq -r '.template.id' "${TEMPLATE_FILE}") wurde ausgewählt."
|
|
log "Auswahl wurde unter ${TEMPLATE_FILE} gespeichert."
|
|
}
|
|
|
|
main() {
|
|
require_root
|
|
prepare_runtime
|
|
validate_server_response
|
|
show_templates
|
|
select_template
|
|
}
|
|
|
|
main "$@"
|