#!/bin/sh set -eu # Läuft im Rettungssystem des Anbieters, mit genau den Werten, die der # Adminbereich in die kopierte Zeile geschrieben hat. Es holt nichts ab: alles, # was vor dem Tunnel gebraucht wird, steht bereits hier (Spec §5). # # Der Ablauf sind Abschnitte. Jeder meldet sich zurück, sobald ein Weg zu # CluPilot existiert; die davor werden lokal mitgeschrieben und nachgereicht. # Die Abschnittsschlüssel sind die einzige Absprache mit dem Plattform-Plan und # stehen unten in `main` in genau der Reihenfolge aus Spec §7. # # Wiederanlauf: die Fortschrittsdatei ist der Zustand. Ein Abschnitt, der schon # `done` gemeldet hat, läuft nicht erneut — so nimmt der systemd-Dienst nach dem # Neustart (Task 3) denselben Lauf wieder auf, statt bei Null anzufangen. CLUPILOT_CODE='' CLUPILOT_WG_PRIVATE='' CLUPILOT_WG_IP='' CLUPILOT_HUB_PUBKEY='' CLUPILOT_HUB_ENDPOINT='' CLUPILOT_API='' # Wird von `run_section` gefüllt, wenn ein Abschnitt der Meldung etwas # mitzugeben hat, und danach wieder geleert. CLUPILOT_SECTION_NOTE='' usage() { cat <<'TEXT' clupilot-bootstrap.sh — macht aus einer Maschine im Rettungssystem einen fertigen Proxmox-Host. --code Ausweis für den Rückweg, 32 Zeichen --wg-private WireGuard-Privatschlüssel, von CluPilot erzeugt --wg-ip zugeteilte Tunnel-Adresse, z. B. 10.66.0.11/24 --hub-pubkey öffentlicher Schlüssel des Hubs --hub-endpoint Adresse des Hubs --api CluPilot über die TUNNEL-Adresse, ohne Schrägstrich am Ende, z. B. http://10.66.0.1 Diese Zeile wird nicht abgetippt. Der Adminbereich zeigt sie fertig zum Kopieren, wenn ein Host angelegt wird. TEXT } # Nach stderr, damit stdout frei bleibt, und zusätzlich in eine Datei — der # Betreiber sieht die Konsole, aber wer hinterher nachsieht, hat nur die Datei. log() { _line="$(date -u '+%Y-%m-%dT%H:%M:%SZ') $*" printf '%s\n' "$_line" >&2 [ -d "${CLUPILOT_STATE_DIR:-}" ] && printf '%s\n' "$_line" >> "${CLUPILOT_STATE_DIR}/bootstrap.log" return 0 } die() { printf 'clupilot-bootstrap: %s\n' "$*" >&2 exit 1 } parse_arguments() { while [ $# -gt 0 ]; do case "$1" in --code) CLUPILOT_CODE="${2:-}"; shift 2 ;; --wg-private) CLUPILOT_WG_PRIVATE="${2:-}"; shift 2 ;; --wg-ip) CLUPILOT_WG_IP="${2:-}"; shift 2 ;; --hub-pubkey) CLUPILOT_HUB_PUBKEY="${2:-}"; shift 2 ;; --hub-endpoint) CLUPILOT_HUB_ENDPOINT="${2:-}"; shift 2 ;; --api) CLUPILOT_API="${2:-}"; shift 2 ;; -h|--help) usage; exit 0 ;; *) usage >&2; die "unbekannte Angabe: $1" ;; esac done # Alle sechs sind Pflicht. Es gibt keine sinnvolle Vorgabe für einen davon, # und ein fehlender fällt sonst erst mitten in einer Installation auf, die # die Platte schon überschrieben hat. [ -n "$CLUPILOT_CODE" ] || die '--code fehlt' [ -n "$CLUPILOT_WG_PRIVATE" ] || die '--wg-private fehlt' [ -n "$CLUPILOT_WG_IP" ] || die '--wg-ip fehlt' [ -n "$CLUPILOT_HUB_PUBKEY" ] || die '--hub-pubkey fehlt' [ -n "$CLUPILOT_HUB_ENDPOINT" ] || die '--hub-endpoint fehlt' [ -n "$CLUPILOT_API" ] || die '--api fehlt' # Ein Schrägstrich am Ende ergäbe `…//host/progress`. Manche Router # beantworten das, manche nicht — und der Unterschied fiele erst beim ersten # Melden auf, also nach dem Tunnelbeitritt. CLUPILOT_API="${CLUPILOT_API%/}" } # Findet `lib/` neben dem Skript. # # OFFEN, und zwar außerhalb dieses Skripts: der Adminbereich zeigt laut # Plattform-Plan Task 7 eine Zeile mit `curl` darin, aber weder Spec noch Plan # sagen, WAS geladen wird. Ein `curl … | sh` kann keine `lib/` haben; der Plan # verlangt aber getrennte Dateien, damit `network.sh` und `template.sh` # unabhängig wiederholbar bleiben. Beides zugleich geht nur, wenn die Zeile ein # Archiv holt und auspackt. Bis das entschieden ist, sucht das Skript seine # Bibliothek neben sich und fällt auf den Ort zurück, an den Task 3 sie kopiert. resolve_lib_dir() { _self_dir="$(dirname -- "$0")" if [ -f "${_self_dir}/lib/report.sh" ]; then printf '%s' "${_self_dir}/lib" return 0 fi if [ -f '/opt/clupilot/bootstrap/lib/report.sh' ]; then printf '%s' '/opt/clupilot/bootstrap/lib' return 0 fi die 'lib/report.sh nicht gefunden — das Skript wurde ohne seine Bibliothek kopiert' } main() { parse_arguments "$@" _lib="$(resolve_lib_dir)" # shellcheck source=lib/report.sh . "${_lib}/report.sh" init_reporting log "Bootstrap beginnt — Tunnel-Adresse ${CLUPILOT_WG_IP}, CluPilot unter ${CLUPILOT_API}" # Vor jedem Abschnitt: was liegengeblieben ist, geht zuerst raus. Nach dem # Tunnelbeitritt ist das der Aufruf, der die ganze Vorgeschichte nachreicht. flush_reports # Die Abschnitte kommen mit den Tasks 2 bis 9 dazu, in der Reihenfolge aus # Spec §7. Der Rumpf steht schon hier, damit sichtbar ist, was noch fehlt: # # run_section rescue_checked section_rescue_checked # Task 2 # run_section debian_installed section_debian_installed # Task 3 # run_section rebooted section_rebooted # Task 3 # run_section proxmox_installed section_proxmox_installed # Task 4 # run_section network_bridged section_network_bridged # Task 5 # run_section wireguard_joined section_wireguard_joined # Task 6 # run_section traefik_running section_traefik_running # Task 7 # run_section template_built section_template_built # Task 8 # run_section registered section_registered # Task 9 log 'Gerüst steht. Es sind noch keine Abschnitte eingehängt (Tasks 2 bis 9).' } main "$@"