#!/bin/bash #=============================================================================== # felhom-bootstrap.sh — invoked by felhom-bootstrap.service, retried until host-install succeeds. # # One attempt: read /etc/felhom/bootstrap.env -> fetch felhom-host-install.sh from the PUBLIC # distribution channel (hub install-command Option-1 URL) -> run it unattended with the customer's # retrieval passphrase -> on rc 0 write the done-flag + disable the unit; else exit non-zero so the # unit retries. Journal-only logging; the passphrase is never echoed and lives only in a 0600 tmpfs # file for the duration of one host-install invocation. # # Retry-vs-resume (source-verified, encoded ONCE): felhom-host-install.sh v1.11.3 makes --resume # safe — its producer steps (token/enroll/grows) re-run every pass, so a resumed install repopulates # hub.host_id/proxmox.token and never writes a crash-loop config. A plain re-invoke over an existing # install state, by contrast, would re-hit the populated-host leaf guard / existing-vmid refusal. # Therefore: FIRST attempt is plain; any later attempt that finds the install state file adds # --resume. (--mode is required in both forms.) State file: /var/lib/felhom-install/state.json. # # NOT production-generic: this is the R-21 bare-metal first-boot bootstrap. It does NOT modify # felhom-host-install.sh; it only invokes it. #=============================================================================== # Deliberately NOT `set -e`: we must capture host-install's exit code and exit on our own terms. set -uo pipefail ENV_FILE=/etc/felhom/bootstrap.env DONE_FLAG=/etc/felhom/.bootstrap-done STATE_FILE=/var/lib/felhom-install/state.json PASS_FILE=/run/felhom-bootstrap-pass SCRIPT_TMP=/run/felhom-host-install.sh log() { echo "felhom-bootstrap: $*"; } cleanup_pass() { [[ -e "$PASS_FILE" ]] && { shred -u "$PASS_FILE" 2>/dev/null || rm -f "$PASS_FILE"; }; return 0; } trap cleanup_pass EXIT # Belt-and-suspenders: the unit already has ConditionPathExists=!done, but guard here too. if [[ -e "$DONE_FLAG" ]]; then log "done-flag present ($DONE_FLAG) — nothing to do" exit 0 fi # --- env ------------------------------------------------------------------------------------------ if [[ ! -r "$ENV_FILE" ]]; then log "ERROR: $ENV_FILE missing or unreadable — cannot bootstrap (no guessed defaults)" exit 1 fi # shellcheck disable=SC1090 source "$ENV_FILE" for var in FELHOM_CUSTOMER_ID FELHOM_MODE FELHOM_RETRIEVAL_PASSPHRASE; do if [[ -z "${!var:-}" ]]; then log "ERROR: $var is unset/empty in $ENV_FILE — refusing to guess" exit 1 fi done HUB_URL="${FELHOM_HUB_URL:-https://hub.felhom.eu}" INSTALL_URL="${FELHOM_INSTALL_URL:-https://felhom.eu/scripts/felhom-host-install.sh}" EXTRA_ARGS="${FELHOM_EXTRA_ARGS:-}" # --- fetch host-install (public channel) ---------------------------------------------------------- log "fetching host-install: $INSTALL_URL" if ! curl -fsSL --max-time 60 "$INSTALL_URL" -o "$SCRIPT_TMP"; then log "ERROR: host-install fetch failed (no network yet?) — unit will retry" exit 1 fi if [[ ! -s "$SCRIPT_TMP" ]]; then log "ERROR: fetched host-install is empty — unit will retry" exit 1 fi # --- retrieval passphrase -> 0600 tmpfs file ------------------------------------------------------ ( umask 077; printf '%s' "$FELHOM_RETRIEVAL_PASSPHRASE" > "$PASS_FILE" ) # --- retry-vs-resume ruling ----------------------------------------------------------------------- args=(--customer-id "$FELHOM_CUSTOMER_ID" --mode "$FELHOM_MODE" --hub-url "$HUB_URL" --passphrase-file "$PASS_FILE") if [[ -f "$STATE_FILE" ]]; then log "prior install state present ($STATE_FILE) -> adding --resume (host-install v1.11.3: producers re-run, safe)" args+=(--resume) fi # EXTRA_ARGS are profile-only flags (never secrets); intentional word-split. read -ra extra <<< "$EXTRA_ARGS" log "running host-install (customer=${FELHOM_CUSTOMER_ID} mode=${FELHOM_MODE} hub=${HUB_URL})" bash "$SCRIPT_TMP" "${args[@]}" "${extra[@]}" rc=$? cleanup_pass if [[ $rc -eq 0 ]]; then log "host-install SUCCESS — writing done-flag, disabling unit, scrubbing env" install -d -m 0755 "$(dirname "$DONE_FLAG")" : > "$DONE_FLAG"; chmod 0644 "$DONE_FLAG" systemctl disable felhom-bootstrap.service 2>/dev/null || true # Reduce secret-at-rest: the box is enrolled; the passphrase is no longer needed. shred -u "$ENV_FILE" 2>/dev/null || rm -f "$ENV_FILE" exit 0 fi log "host-install FAILED rc=${rc} — unit will retry in 30s" exit "$rc"