#!/usr/bin/env bash set -Eeuo pipefail # Dieses Skript wird von einem Orchestrator-Modul (z.B. 40_backend.sh) per # `source` in dessen Shell geladen. Variablen bleiben deshalb bewusst nicht # readonly, um Namenskollisionen mit dem ladenden Modul zu vermeiden. BACKEND_KEY="fedora" BACKEND_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" KICKSTART_TEMPLATE="${BACKEND_DIR}/kickstart.tpl" RUNTIME_BLUEPRINT_FILE="/run/tuxflotte/runtime/runtime_blueprint.json" SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json" # Von 10_hardware.sh im selben Live-Boot geschrieben (siehe dort) - Quelle # fuer den Fingerprint, der jetzt auch auf dem installierten Geraet selbst # hinterlegt wird (siehe backend_generate_config()/kickstart.tpl %post). HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json" RUNTIME_DIR="/run/tuxflotte/backend" CONFIG_FILE="${RUNTIME_DIR}/config" backend_log() { printf '[backend:%s] %s\n' "${BACKEND_KEY}" "$*" >&2 } backend_fatal() { printf '[backend:%s] FEHLER: %s\n' "${BACKEND_KEY}" "$*" >&2 return 1 } backend_init() { for cmd in jq envsubst; do command -v "${cmd}" >/dev/null 2>&1 || { backend_fatal "Benötigtes Werkzeug fehlt: ${cmd}"; return 1; } done [[ -r "${KICKSTART_TEMPLATE}" ]] || { backend_fatal "Kickstart-Template nicht gefunden: ${KICKSTART_TEMPLATE}"; return 1; } install -d \ --mode=0700 \ --owner=root \ --group=root \ "${RUNTIME_DIR}" rm -f -- "${CONFIG_FILE}" backend_log "Initialisiert." } backend_validate() { [[ -r "${RUNTIME_BLUEPRINT_FILE}" ]] || { backend_fatal "Runtime Blueprint nicht gefunden: ${RUNTIME_BLUEPRINT_FILE}"; return 1; } jq --exit-status \ --arg backend_key "${BACKEND_KEY}" \ '.runtime_blueprint.backend_id == $backend_key' \ "${RUNTIME_BLUEPRINT_FILE}" >/dev/null || { backend_fatal "Runtime Blueprint ist nicht für Backend '${BACKEND_KEY}' aufgelöst."; return 1; } jq --exit-status ' .runtime_blueprint.installation_directives | (.disk_encryption | type == "boolean") and (.partitioning | type == "string") and (.secure_boot_required | type == "boolean") ' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null || { backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; } backend_log "Runtime Blueprint ist gültig für Backend '${BACKEND_KEY}'." } backend_generate_config() { local hostname local device_id local disk_encryption local partitioning local secure_boot_required local partitioning_command local blueprints_json [[ -r "${SERVER_RESPONSE_FILE}" ]] || { backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; } hostname="$(jq --raw-output '.device.hostname // empty' "${SERVER_RESPONSE_FILE}")" [[ -n "${hostname}" ]] || { backend_fatal "Kein Hostname in der Serverantwort gefunden."; return 1; } device_id="$(jq --raw-output '.device.id // empty' "${SERVER_RESPONSE_FILE}")" [[ -n "${device_id}" ]] || { backend_fatal "Keine Geräte-ID in der Serverantwort gefunden."; return 1; } # Fuer die beidseitige Identifikation (Geraeteliste <-> Geraet selbst, # siehe kickstart.tpl %post) - aus der bereits waehrend des Live-Boots # berechneten hardware.json, nicht aus der Serverantwort (die kennt nur # die zugewiesene device_id, nicht den urspruenglichen Hardware-Hash). local device_fingerprint [[ -r "${HARDWARE_FILE}" ]] || { backend_fatal "Hardware-Erfassung nicht gefunden: ${HARDWARE_FILE}"; return 1; } device_fingerprint="$(jq --raw-output '.identity.device_fingerprint // empty' "${HARDWARE_FILE}")" [[ -n "${device_fingerprint}" ]] || { backend_fatal "Kein device_fingerprint in ${HARDWARE_FILE} gefunden."; return 1; } disk_encryption="$(jq --raw-output '.runtime_blueprint.installation_directives.disk_encryption' "${RUNTIME_BLUEPRINT_FILE}")" partitioning="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning' "${RUNTIME_BLUEPRINT_FILE}")" secure_boot_required="$(jq --raw-output '.runtime_blueprint.installation_directives.secure_boot_required' "${RUNTIME_BLUEPRINT_FILE}")" case "${partitioning}" in default) if [[ "${disk_encryption}" == "true" ]]; then partitioning_command="autopart --encrypted" else partitioning_command="autopart" fi ;; *) backend_fatal "Nicht unterstützte Partitionierungsvorgabe: ${partitioning}" return 1 ;; esac if [[ "${secure_boot_required}" == "true" ]]; then backend_log "Hinweis: secure_boot_required=true wird derzeit nicht in der Kickstart-Konfiguration durchgesetzt (Phase 1)." fi blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")" TUXFLOTTE_HOSTNAME="${hostname}" \ TUXFLOTTE_DEVICE_ID="${device_id}" \ TUXFLOTTE_PARTITIONING_COMMAND="${partitioning_command}" \ TUXFLOTTE_BLUEPRINTS_JSON="${blueprints_json}" \ TUXFLOTTE_DEVICE_FINGERPRINT="${device_fingerprint}" \ envsubst '${TUXFLOTTE_HOSTNAME} ${TUXFLOTTE_DEVICE_ID} ${TUXFLOTTE_PARTITIONING_COMMAND} ${TUXFLOTTE_BLUEPRINTS_JSON} ${TUXFLOTTE_DEVICE_FINGERPRINT}' \ <"${KICKSTART_TEMPLATE}" >"${CONFIG_FILE}" chmod 0600 "${CONFIG_FILE}" [[ -s "${CONFIG_FILE}" ]] || { backend_fatal "Erzeugte Konfigurationsdatei ist leer: ${CONFIG_FILE}"; return 1; } if grep -q '\${TUXFLOTTE_' "${CONFIG_FILE}"; then backend_fatal "Erzeugte Konfigurationsdatei enthält nicht aufgelöste Platzhalter." return 1 fi backend_log "Konfiguration erzeugt: ${CONFIG_FILE}" } backend_launch() { backend_log "Phase 1: Start des nativen Installers ist noch nicht aktiv." backend_log "Erzeugte Konfiguration liegt bereit unter: ${CONFIG_FILE}" } backend_postinstall() { backend_log "Provisioning-Agent-Einrichtung erfolgt im %post-Abschnitt der Kickstart-Konfiguration (Agent-Abruf, Bootstrap-Registrierung, systemd-Aktivierung)." }