Files
homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh
T
Micha e4b0db2af6 Add Komodo bootstrap dry-run scaffold (F-09 rest)
Mirror of the Immich restore-test pattern for the Komodo bootstrap
anchor. Brings up a throwaway komodo-mongo + komodo-core +
komodo-periphery under project restoretest-komodo, isolated from
production:

- same image digests as production (mongo:7.0.32, komodo-core:2,
  komodo-periphery:2) to prove compose-level bootstrap compatibility
- restore-lab paths under /mnt/user/backups/restore-lab/komodo
- 127.0.0.1:19120 only, no LAN bind, no Traefik, no Authelia
- test periphery runs WITHOUT docker.sock mount and WITHOUT
  /mnt/user/services mount; cannot manage productive containers
- KOMODO_* secrets are throwaway placeholders hardcoded in the test
  compose; productive secrets never enter this path

Smoke test: compose config valid, mongo healthy, mongo auth-ping
with test creds, komodo-core HTTP 200/302/303/401, periphery
container running. Report under restore-reports/komodo-bootstrap-*.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:25:41 +02:00

136 lines
4.3 KiB
Bash

#!/bin/bash
set -euo pipefail
# Komodo Bootstrap Trockenlauf
#
# Verifiziert, dass `ops/komodo/docker-compose.yml` als Recovery-Anker
# tauglich ist: Wegwerf-Mongo, Wegwerf-Core, Wegwerf-Periphery werden
# isoliert hochgefahren und auf Bootstrap-Faehigkeit geprueft.
#
# Produktive Komodo-Container, produktive Mongo-Datadir und produktive
# Komodo-Secrets werden NICHT angefasst.
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"
WHATIF=0
KEEP_DATA=0
for arg in "$@"; do
case "$arg" in
--what-if) WHATIF=1 ;;
--keep-data) KEEP_DATA=1 ;;
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
esac
done
RESTORE_ROOT="/mnt/user/backups/restore-lab/komodo"
REPORT_ROOT="/mnt/user/backups/restore-reports"
COMPOSE_FILE="$SCRIPT_DIR/komodo-bootstrap-compose.test.yml"
PROJECT_NAME="restoretest-komodo"
REPORT_FILE="$REPORT_ROOT/komodo-bootstrap-$(date +%F).md"
if [ "$WHATIF" -eq 1 ]; then
cat <<EOF
Komodo bootstrap trockenlauf
Mode: WhatIf
RestoreRoot: $RESTORE_ROOT
ReportRoot: $REPORT_ROOT
Planned isolation:
- Test-Mongo: mongo:7.0.32 (gleicher Digest wie Produktion), Datadir $RESTORE_ROOT/mongo
- Test-Core: ghcr.io/moghtech/komodo-core:2 (gleicher Digest wie Produktion), Port 127.0.0.1:19120
- Test-Periphery: ghcr.io/moghtech/komodo-periphery:2, ohne docker.sock-Mount
- KOMODO_*-Secrets: Wegwerf-Werte ausschliesslich fuer Trockenlauf
- Compose-Project: $PROJECT_NAME (isoliert von "komodo")
Smoke-Test:
- compose config valid
- Mongo healthy
- Core HTTP 200/4xx auf 127.0.0.1:19120 (Login-Seite erwartet)
- Periphery container running
EOF
exit 0
fi
require_cmd docker
require_path "$COMPOSE_FILE"
cleanup() {
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" down -v >/dev/null 2>&1 || true
if [ "$KEEP_DATA" -ne 1 ]; then
rm -rf "$RESTORE_ROOT"
fi
}
trap cleanup EXIT
rm -rf "$RESTORE_ROOT"
mkdir -p "$RESTORE_ROOT/mongo" "$RESTORE_ROOT/core" "$RESTORE_ROOT/keys" "$RESTORE_ROOT/periphery"
# Stufe 1: Compose syntaktisch validieren
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" config >/dev/null
# Stufe 2: Mongo und Core hochfahren
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" up -d \
restoretest-komodo-mongo restoretest-komodo-core >/dev/null
# Stufe 3: Warten auf Mongo healthy
mongo_ok=0
for _ in $(seq 1 30); do
s="$(docker inspect restoretest-komodo-mongo --format '{{.State.Health.Status}}' 2>/dev/null || true)"
if [ "$s" = "healthy" ]; then mongo_ok=1; break; fi
sleep 2
done
if [ "$mongo_ok" -ne 1 ]; then
echo "Test-Mongo never reported healthy" >&2
docker logs --tail 80 restoretest-komodo-mongo >&2 || true
exit 1
fi
# Stufe 4: Warten bis Core HTTP antwortet
http_status=""
for _ in $(seq 1 60); do
http_status="$(curl -s -o /tmp/komodo-bootstrap-body.html -w '%{http_code}' -L http://127.0.0.1:19120 || true)"
if [ "$http_status" = "200" ] || [ "$http_status" = "302" ] || [ "$http_status" = "303" ] || [ "$http_status" = "401" ]; then
break
fi
sleep 2
done
# Stufe 5: Periphery dazustarten und Health pruefen
docker compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" up -d \
restoretest-komodo-periphery >/dev/null
sleep 8
periphery_state="$(docker inspect restoretest-komodo-periphery --format '{{.State.Status}}' 2>/dev/null || echo missing)"
# Stufe 6: Mongo-Ping mit Test-Credentials als zusaetzlicher Sanity-Check
mongo_ping="n/a"
if docker exec restoretest-komodo-mongo mongosh --quiet -u komodo \
-p restoretest-komodo-mongo-pwd --authenticationDatabase admin \
--eval 'db.adminCommand({ping:1}).ok' 2>/dev/null | grep -q '^1$'; then
mongo_ping="ok"
fi
write_report "$REPORT_FILE" <<EOF
# Komodo Bootstrap Trockenlauf - $(date +%F)
- Compose: \`ops/restore-tests/komodo-bootstrap-compose.test.yml\`
- Project: \`$PROJECT_NAME\`
- Restore root: \`$RESTORE_ROOT\`
- Test endpoint: \`http://127.0.0.1:19120\`
- Result: \`SUCCESS\`
## Checks
- docker compose config valid: \`ok\`
- Test-Mongo healthy: \`ok\`
- Mongo authenticated ping (Test-Creds): \`$mongo_ping\`
- Komodo Core HTTP status: \`$http_status\`
- Test-Periphery container state: \`$periphery_state\`
## Notes
- Produktive Komodo-Container, Mongo-Datadir und Secrets wurden nicht beruehrt.
- Test-Periphery laeuft bewusst ohne docker.sock-Mount.
- Test-Daten wurden \`$([ "$KEEP_DATA" -eq 1 ] && echo behalten || echo bereinigt)\`.
EOF
echo "Komodo bootstrap trockenlauf ok -> $REPORT_FILE"