e4b0db2af6
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>
136 lines
4.3 KiB
Bash
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"
|