146 lines
5.8 KiB
Bash
Executable File
146 lines
5.8 KiB
Bash
Executable File
#!/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 <einmal-code> Ausweis für den Rückweg, 32 Zeichen
|
|
--wg-private <schlüssel> WireGuard-Privatschlüssel, von CluPilot erzeugt
|
|
--wg-ip <adresse/präfix> zugeteilte Tunnel-Adresse, z. B. 10.66.0.11/24
|
|
--hub-pubkey <schlüssel> öffentlicher Schlüssel des Hubs
|
|
--hub-endpoint <host:port> Adresse des Hubs
|
|
--api <url> 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 "$@"
|