installer: Installations-Meilensteine/Fehlschlaege an anode melden
Neue scripts/lib/reporting.sh (tuxflotte_report_installation_event())
meldet best-effort an POST /api/v1/devices/{device_id}/installation-events
(device_fingerprint-authentifiziert, siehe provisioning-server-Commit
51fbf0f) - ein Fehlschlag beim Melden selbst darf die eigentliche
Installation nie aufhalten.
Vier Meldepunkte:
- "activation_confirmed" direkt nach erfolgreichem Provisioning-Handshake
(15_server_handshake.sh)
- "installation_started" direkt nach bestaetigtem Commit Point
(installer.sh)
- "installation_completed" ganz am Ende von backend_postinstall(), vor dem
finalen Reboot (backend.sh)
- "installation_failed" zentral in boot-autostart.sh (einziger Ort, an dem
der echte Exit-Code von installer.sh bekannt ist, ohne jedes Modul
einzeln instrumentieren zu muessen) - Detail = letzte 40 Logzeilen,
enthalten bereits die eigentliche [FEHLER]-Meldung des gescheiterten
Moduls. Nur bei STATUS != 0, nicht bei einem kontrollierten Abbruch an
einem Commit-Gate (STATUS = 0).
Nutzer-Wunsch (01.09.2026, nach dem ersten echten Hardware-Test):
Fehlschlaege waehrend der Installation sichtbar machen, ohne am
Bildschirm mitschreiben zu muessen ("das ist kein Flow... fuer die
Weiterentwicklung eines irgendwann fehlerfreien Betriebs sind fuer uns
diese Meldungen Gold wert").
Live in QEMU end-to-end verifiziert: alle drei Erfolgs-Meilensteine
korrekt in device_installation_events angekommen (activation_confirmed,
installation_started, installation_completed), vollstaendiger Durchlauf
bis zum echten Mint-Cinnamon-Login-Bildschirm nach Reboot bestaetigt.
This commit is contained in:
parent
43a18074e0
commit
d496adad09
@ -22,6 +22,7 @@ REPO_DIR="$(cd "${BACKEND_DIR}/../.." && pwd)"
|
||||
POSTINSTALL_SCRIPT="${BACKEND_DIR}/postinstall.sh"
|
||||
IMAGE_DEPLOY_LIB="${REPO_DIR}/scripts/lib/image_deploy.sh"
|
||||
BOOT_MEDIUM_LIB="${REPO_DIR}/scripts/lib/boot_medium.sh"
|
||||
REPORTING_LIB="${REPO_DIR}/scripts/lib/reporting.sh"
|
||||
|
||||
# Vom Netzwerkmodul geschuetzt abgelegtes WLAN-/Ethernet-Verbindungsprofil
|
||||
# (siehe export_connection_profile() in 05_network.sh) - existiert nur,
|
||||
@ -108,6 +109,11 @@ backend_init() {
|
||||
# shellcheck source=../../scripts/lib/boot_medium.sh
|
||||
source "${BOOT_MEDIUM_LIB}"
|
||||
|
||||
[[ -r "${REPORTING_LIB}" ]] ||
|
||||
{ backend_fatal "Reporting-Bibliothek nicht gefunden: ${REPORTING_LIB}"; return 1; }
|
||||
# shellcheck source=../../scripts/lib/reporting.sh
|
||||
source "${REPORTING_LIB}"
|
||||
|
||||
[[ -r "${POSTINSTALL_SCRIPT}" ]] ||
|
||||
{ backend_fatal "Postinstall-Skript nicht gefunden: ${POSTINSTALL_SCRIPT}"; return 1; }
|
||||
|
||||
@ -334,6 +340,8 @@ backend_postinstall() {
|
||||
umount --recursive "${TARGET_DIR}" ||
|
||||
{ backend_fatal "${TARGET_DIR} konnte nicht ausgehängt werden."; return 1; }
|
||||
|
||||
tuxflotte_report_installation_event "installation_completed"
|
||||
|
||||
# Nutzer-Feedback (01.09.2026, echter Hardware-Test): akustischer Hinweis
|
||||
# + klare Ansage, dass der USB-Stick jetzt gefahrlos gezogen werden kann
|
||||
# (ab hier wird nur noch von der Zielplatte gebootet) - Bestaetigung mit
|
||||
|
||||
@ -22,6 +22,7 @@ REPO_DIR="$(cd "${BACKEND_DIR}/../.." && pwd)"
|
||||
POSTINSTALL_SCRIPT="${BACKEND_DIR}/postinstall.sh"
|
||||
IMAGE_DEPLOY_LIB="${REPO_DIR}/scripts/lib/image_deploy.sh"
|
||||
BOOT_MEDIUM_LIB="${REPO_DIR}/scripts/lib/boot_medium.sh"
|
||||
REPORTING_LIB="${REPO_DIR}/scripts/lib/reporting.sh"
|
||||
|
||||
# Vom Netzwerkmodul geschuetzt abgelegtes WLAN-/Ethernet-Verbindungsprofil
|
||||
# (siehe export_connection_profile() in 05_network.sh) - existiert nur,
|
||||
@ -108,6 +109,11 @@ backend_init() {
|
||||
# shellcheck source=../../scripts/lib/boot_medium.sh
|
||||
source "${BOOT_MEDIUM_LIB}"
|
||||
|
||||
[[ -r "${REPORTING_LIB}" ]] ||
|
||||
{ backend_fatal "Reporting-Bibliothek nicht gefunden: ${REPORTING_LIB}"; return 1; }
|
||||
# shellcheck source=../../scripts/lib/reporting.sh
|
||||
source "${REPORTING_LIB}"
|
||||
|
||||
[[ -r "${POSTINSTALL_SCRIPT}" ]] ||
|
||||
{ backend_fatal "Postinstall-Skript nicht gefunden: ${POSTINSTALL_SCRIPT}"; return 1; }
|
||||
|
||||
@ -334,6 +340,8 @@ backend_postinstall() {
|
||||
umount --recursive "${TARGET_DIR}" ||
|
||||
{ backend_fatal "${TARGET_DIR} konnte nicht ausgehängt werden."; return 1; }
|
||||
|
||||
tuxflotte_report_installation_event "installation_completed"
|
||||
|
||||
# Nutzer-Feedback (01.09.2026, echter Hardware-Test): akustischer Hinweis
|
||||
# + klare Ansage, dass der USB-Stick jetzt gefahrlos gezogen werden kann
|
||||
# (ab hier wird nur noch von der Zielplatte gebootet) - Bestaetigung mit
|
||||
|
||||
@ -44,6 +44,19 @@ export TUXFLOTTE_LOG_FILE="${LOG_FILE}"
|
||||
/opt/tuxflotte/scripts/installer.sh 2>&1 | tee -a "${LOG_FILE}"
|
||||
STATUS="${PIPESTATUS[0]}"
|
||||
|
||||
# Nutzer-Wunsch (01.09.2026): Fehlschlaege sollen sich melden, ohne dass am
|
||||
# Bildschirm mitgeschrieben werden muss ("Gold wert" fuer die eigene
|
||||
# Fehlersuche). Nur bei echtem Fehlschlag (STATUS != 0) - ein kontrollierter
|
||||
# Abbruch an einem Commit-Gate (Nutzer sagt "N") beendet installer.sh
|
||||
# ebenfalls, aber mit "exit 0", das ist kein Fehler. Detail = die letzten
|
||||
# Logzeilen (enthalten bereits die eigentliche [FEHLER]-Meldung des
|
||||
# gescheiterten Moduls) - best effort, siehe reporting.sh.
|
||||
if [[ "${STATUS}" -ne 0 ]]; then
|
||||
# shellcheck source=lib/reporting.sh
|
||||
source /opt/tuxflotte/scripts/lib/reporting.sh
|
||||
tuxflotte_report_installation_event "installation_failed" "$(tail -n 40 "${LOG_FILE}" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# Live gefunden (31.08.2026): ein ExecStopPost, der beim Dienstende
|
||||
# getty@tty1.service neu startet, ist unzuverlaessig (Race mit dem eigenen
|
||||
# TTY-Teardown dieses Dienstes - der Job wurde angestossen, blieb aber
|
||||
|
||||
@ -8,6 +8,7 @@ source "$SCRIPT_DIR/lib/logging.sh"
|
||||
source "$SCRIPT_DIR/lib/errors.sh"
|
||||
source "$SCRIPT_DIR/lib/utils.sh"
|
||||
source "$SCRIPT_DIR/lib/checks.sh"
|
||||
source "$SCRIPT_DIR/lib/reporting.sh"
|
||||
|
||||
DRY_RUN=false
|
||||
|
||||
@ -65,6 +66,7 @@ source "$INSTALLATION_STATE_FILE"
|
||||
case "${TUXFLOTTE_INSTALLATION_CONFIRMED:-}" in
|
||||
true)
|
||||
log_info "Commit Point bestätigt. Installationsphase wird fortgesetzt."
|
||||
tuxflotte_report_installation_event "installation_started"
|
||||
;;
|
||||
false)
|
||||
log_info "Provisionierung wurde durch den Benutzer kontrolliert beendet."
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Meldet Installations-Meilensteine/Fehlschlaege an anode (device_installation_events,
|
||||
# siehe Migration 0025 in provisioning-server) - ausschliesslich fuer die eigene
|
||||
# Fehlersuche/Betriebsentwicklung gedacht ("Gold wert" fuer den Support, Nutzer-Wunsch
|
||||
# 01.09.2026 nach dem ersten echten Hardware-Test), noch NICHT zwangslaeufig auf der
|
||||
# Kunden-Oberflaeche sichtbar - das ist eine separate, noch offene Entscheidung.
|
||||
#
|
||||
# Rein melde-basiert und best effort: das Geraet hat waehrend der Installation noch
|
||||
# kein agent_secret (das entsteht erst ganz am Ende in backend_postinstall()), deshalb
|
||||
# device_fingerprint als Nachweis statt eines Service-Tokens (siehe
|
||||
# InstallationEventRequest/device_fingerprint_matches() serverseitig - gleiches
|
||||
# Vertrauensniveau wie /api/v1/activate selbst). Ein Fehlschlag beim Melden selbst
|
||||
# (Netzwerk gerade weg, Server nicht erreichbar, Geraet noch nicht aktiviert) darf die
|
||||
# eigentliche Installation NIE aufhalten - deshalb "|| true" ueberall, kein "set -e"-
|
||||
# Abbruch moeglich, keine Rueckgabewert-Pruefung durch die Aufrufer noetig.
|
||||
tuxflotte_report_installation_event() {
|
||||
local event_type="$1"
|
||||
local detail="${2:-}"
|
||||
|
||||
local response_file="/run/tuxflotte/server/response.json"
|
||||
local hardware_file="/run/tuxflotte/hardware/hardware.json"
|
||||
local network_state="/run/tuxflotte/network/state.env"
|
||||
|
||||
[[ -r "${response_file}" && -r "${hardware_file}" && -r "${network_state}" ]] || return 0
|
||||
|
||||
local device_id device_fingerprint server_url payload
|
||||
device_id="$(jq --raw-output '.device.id // empty' "${response_file}" 2>/dev/null)"
|
||||
device_fingerprint="$(jq --raw-output '.identity.device_fingerprint // empty' "${hardware_file}" 2>/dev/null)"
|
||||
|
||||
[[ -n "${device_id}" && -n "${device_fingerprint}" ]] || return 0
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${network_state}" 2>/dev/null || return 0
|
||||
server_url="${TUXFLOTTE_SERVER_URL%/health}"
|
||||
[[ -n "${server_url}" ]] || return 0
|
||||
|
||||
payload="$(
|
||||
jq --null-input \
|
||||
--arg device_fingerprint "${device_fingerprint}" \
|
||||
--arg event_type "${event_type}" \
|
||||
--arg detail "${detail}" \
|
||||
'{
|
||||
device_fingerprint: $device_fingerprint,
|
||||
event_type: $event_type,
|
||||
detail: (if $detail == "" then null else $detail end)
|
||||
}' 2>/dev/null
|
||||
)"
|
||||
[[ -n "${payload}" ]] || return 0
|
||||
|
||||
curl \
|
||||
--silent \
|
||||
--show-error \
|
||||
--fail \
|
||||
--location \
|
||||
--max-time 5 \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-binary "${payload}" \
|
||||
"${server_url}/api/v1/devices/${device_id}/installation-events" \
|
||||
>/dev/null 2>&1 || true
|
||||
}
|
||||
@ -4,6 +4,11 @@ set -Eeuo pipefail
|
||||
|
||||
readonly SCRIPT_NAME="${0##*/}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
readonly SCRIPT_DIR
|
||||
# shellcheck source=../lib/reporting.sh
|
||||
source "${SCRIPT_DIR}/../lib/reporting.sh"
|
||||
|
||||
readonly NETWORK_STATE="/run/tuxflotte/network/state.env"
|
||||
readonly HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json"
|
||||
|
||||
@ -121,6 +126,7 @@ send_activation_request() {
|
||||
fatal "Provisioning-Server hat die Aktivierung abgelehnt."
|
||||
|
||||
log "Provisioning-Handshake erfolgreich abgeschlossen."
|
||||
tuxflotte_report_installation_event "activation_confirmed"
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
@ -44,6 +44,19 @@ export TUXFLOTTE_LOG_FILE="${LOG_FILE}"
|
||||
/opt/tuxflotte/scripts/installer.sh 2>&1 | tee -a "${LOG_FILE}"
|
||||
STATUS="${PIPESTATUS[0]}"
|
||||
|
||||
# Nutzer-Wunsch (01.09.2026): Fehlschlaege sollen sich melden, ohne dass am
|
||||
# Bildschirm mitgeschrieben werden muss ("Gold wert" fuer die eigene
|
||||
# Fehlersuche). Nur bei echtem Fehlschlag (STATUS != 0) - ein kontrollierter
|
||||
# Abbruch an einem Commit-Gate (Nutzer sagt "N") beendet installer.sh
|
||||
# ebenfalls, aber mit "exit 0", das ist kein Fehler. Detail = die letzten
|
||||
# Logzeilen (enthalten bereits die eigentliche [FEHLER]-Meldung des
|
||||
# gescheiterten Moduls) - best effort, siehe reporting.sh.
|
||||
if [[ "${STATUS}" -ne 0 ]]; then
|
||||
# shellcheck source=lib/reporting.sh
|
||||
source /opt/tuxflotte/scripts/lib/reporting.sh
|
||||
tuxflotte_report_installation_event "installation_failed" "$(tail -n 40 "${LOG_FILE}" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# Live gefunden (31.08.2026): ein ExecStopPost, der beim Dienstende
|
||||
# getty@tty1.service neu startet, ist unzuverlaessig (Race mit dem eigenen
|
||||
# TTY-Teardown dieses Dienstes - der Job wurde angestossen, blieb aber
|
||||
|
||||
@ -8,6 +8,7 @@ source "$SCRIPT_DIR/lib/logging.sh"
|
||||
source "$SCRIPT_DIR/lib/errors.sh"
|
||||
source "$SCRIPT_DIR/lib/utils.sh"
|
||||
source "$SCRIPT_DIR/lib/checks.sh"
|
||||
source "$SCRIPT_DIR/lib/reporting.sh"
|
||||
|
||||
DRY_RUN=false
|
||||
|
||||
@ -65,6 +66,7 @@ source "$INSTALLATION_STATE_FILE"
|
||||
case "${TUXFLOTTE_INSTALLATION_CONFIRMED:-}" in
|
||||
true)
|
||||
log_info "Commit Point bestätigt. Installationsphase wird fortgesetzt."
|
||||
tuxflotte_report_installation_event "installation_started"
|
||||
;;
|
||||
false)
|
||||
log_info "Provisionierung wurde durch den Benutzer kontrolliert beendet."
|
||||
|
||||
61
scripts/lib/reporting.sh
Normal file
61
scripts/lib/reporting.sh
Normal file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Meldet Installations-Meilensteine/Fehlschlaege an anode (device_installation_events,
|
||||
# siehe Migration 0025 in provisioning-server) - ausschliesslich fuer die eigene
|
||||
# Fehlersuche/Betriebsentwicklung gedacht ("Gold wert" fuer den Support, Nutzer-Wunsch
|
||||
# 01.09.2026 nach dem ersten echten Hardware-Test), noch NICHT zwangslaeufig auf der
|
||||
# Kunden-Oberflaeche sichtbar - das ist eine separate, noch offene Entscheidung.
|
||||
#
|
||||
# Rein melde-basiert und best effort: das Geraet hat waehrend der Installation noch
|
||||
# kein agent_secret (das entsteht erst ganz am Ende in backend_postinstall()), deshalb
|
||||
# device_fingerprint als Nachweis statt eines Service-Tokens (siehe
|
||||
# InstallationEventRequest/device_fingerprint_matches() serverseitig - gleiches
|
||||
# Vertrauensniveau wie /api/v1/activate selbst). Ein Fehlschlag beim Melden selbst
|
||||
# (Netzwerk gerade weg, Server nicht erreichbar, Geraet noch nicht aktiviert) darf die
|
||||
# eigentliche Installation NIE aufhalten - deshalb "|| true" ueberall, kein "set -e"-
|
||||
# Abbruch moeglich, keine Rueckgabewert-Pruefung durch die Aufrufer noetig.
|
||||
tuxflotte_report_installation_event() {
|
||||
local event_type="$1"
|
||||
local detail="${2:-}"
|
||||
|
||||
local response_file="/run/tuxflotte/server/response.json"
|
||||
local hardware_file="/run/tuxflotte/hardware/hardware.json"
|
||||
local network_state="/run/tuxflotte/network/state.env"
|
||||
|
||||
[[ -r "${response_file}" && -r "${hardware_file}" && -r "${network_state}" ]] || return 0
|
||||
|
||||
local device_id device_fingerprint server_url payload
|
||||
device_id="$(jq --raw-output '.device.id // empty' "${response_file}" 2>/dev/null)"
|
||||
device_fingerprint="$(jq --raw-output '.identity.device_fingerprint // empty' "${hardware_file}" 2>/dev/null)"
|
||||
|
||||
[[ -n "${device_id}" && -n "${device_fingerprint}" ]] || return 0
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${network_state}" 2>/dev/null || return 0
|
||||
server_url="${TUXFLOTTE_SERVER_URL%/health}"
|
||||
[[ -n "${server_url}" ]] || return 0
|
||||
|
||||
payload="$(
|
||||
jq --null-input \
|
||||
--arg device_fingerprint "${device_fingerprint}" \
|
||||
--arg event_type "${event_type}" \
|
||||
--arg detail "${detail}" \
|
||||
'{
|
||||
device_fingerprint: $device_fingerprint,
|
||||
event_type: $event_type,
|
||||
detail: (if $detail == "" then null else $detail end)
|
||||
}' 2>/dev/null
|
||||
)"
|
||||
[[ -n "${payload}" ]] || return 0
|
||||
|
||||
curl \
|
||||
--silent \
|
||||
--show-error \
|
||||
--fail \
|
||||
--location \
|
||||
--max-time 5 \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-binary "${payload}" \
|
||||
"${server_url}/api/v1/devices/${device_id}/installation-events" \
|
||||
>/dev/null 2>&1 || true
|
||||
}
|
||||
@ -4,6 +4,11 @@ set -Eeuo pipefail
|
||||
|
||||
readonly SCRIPT_NAME="${0##*/}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
readonly SCRIPT_DIR
|
||||
# shellcheck source=../lib/reporting.sh
|
||||
source "${SCRIPT_DIR}/../lib/reporting.sh"
|
||||
|
||||
readonly NETWORK_STATE="/run/tuxflotte/network/state.env"
|
||||
readonly HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json"
|
||||
|
||||
@ -121,6 +126,7 @@ send_activation_request() {
|
||||
fatal "Provisioning-Server hat die Aktivierung abgelehnt."
|
||||
|
||||
log "Provisioning-Handshake erfolgreich abgeschlossen."
|
||||
tuxflotte_report_installation_event "activation_confirmed"
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user