From b11fa1cb766a0d6397b127be81383b2b8b801912 Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Tue, 14 Jul 2026 13:26:48 +0200 Subject: [PATCH] feat: add device status interaction and early abort --- scripts/installer.sh | 21 +++++ scripts/modules/17_device_status.sh | 127 ++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100755 scripts/modules/17_device_status.sh diff --git a/scripts/installer.sh b/scripts/installer.sh index 0477195..9570e5b 100755 --- a/scripts/installer.sh +++ b/scripts/installer.sh @@ -29,6 +29,27 @@ run_module "$SCRIPT_DIR/modules/00_preflight.sh" "always" run_module "$SCRIPT_DIR/modules/05_network.sh" "always" run_module "$SCRIPT_DIR/modules/10_hardware.sh" "always" run_module "$SCRIPT_DIR/modules/15_server_handshake.sh" "always" +run_module "$SCRIPT_DIR/modules/17_device_status.sh" "always" +PROVISIONING_STATE_FILE="/run/tuxflotte/provisioning/state.env" + +[[ -r "$PROVISIONING_STATE_FILE" ]] || + error_exit "Provisionierungszustand fehlt: $PROVISIONING_STATE_FILE" + +# shellcheck disable=SC1090 +source "$PROVISIONING_STATE_FILE" + +case "${TUXFLOTTE_PROVISIONING_CONTINUE:-}" in + true) + log_info "Provisionierung wird fortgesetzt." + ;; + false) + log_info "Provisionierung wurde durch den Benutzer kontrolliert beendet." + exit 0 + ;; + *) + error_exit "Ungültiger Provisionierungszustand." + ;; +esac run_module "$SCRIPT_DIR/modules/20_profile_selection.sh" "always" run_module "$SCRIPT_DIR/modules/25_installation_confirm.sh" "always" diff --git a/scripts/modules/17_device_status.sh b/scripts/modules/17_device_status.sh new file mode 100755 index 0000000..7cf42f9 --- /dev/null +++ b/scripts/modules/17_device_status.sh @@ -0,0 +1,127 @@ +#!/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 + + 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 "$@"