#!/bin/bash # Migriert die MongoDB-Datenbank in-place auf Version 7.0. # # MongoDB erlaubt keine Sprünge über mehrere Major-Versionen, daher wird # schrittweise migriert (4.4 -> 5.0 -> 6.0 -> 7.0) und nach jedem Schritt die # featureCompatibilityVersion angehoben. # # Vorher wird geprüft, ob die CPU das überhaupt kann (MongoDB 5+ braucht auf # x86_64 AVX, auf ARM64 ARMv8.2) — ohne das bricht das Skript ab, ohne etwas # zu verändern. Außerdem wird ein Komplett-Backup erstellt. set -euo pipefail cd "$(dirname "$0")" TARGET="7.0" MIGRATION_PATH=("5.0" "6.0" "7.0") DB_DATA="$PWD/data/mongodb" TMP_NAME="unifi-db-migrate" # ---------- 1. CPU-Prüfung ---------- arch="$(uname -m)" flags="$(grep -m1 -iE '^(flags|Features)' /proc/cpuinfo 2>/dev/null || true)" cpu_ok=false case "$arch" in x86_64) grep -qw avx <<< "$flags" && cpu_ok=true ;; aarch64|arm64) grep -qw asimddp <<< "$flags" && cpu_ok=true ;; esac if [[ "$cpu_ok" != true ]]; then echo "ABBRUCH: Diese CPU ($arch) unterstützt kein AVX bzw. ARMv8.2." echo "MongoDB 5+ würde auf diesem Rechner nicht starten — Migration nicht möglich." echo "Es wurde nichts verändert." exit 1 fi echo "==> CPU-Prüfung bestanden ($arch): Migration auf mongo:$TARGET möglich." # ---------- 2. Ausgangslage prüfen ---------- [[ -f .env ]] || { echo "FEHLER: .env fehlt."; exit 1; } CURRENT="$(grep '^MONGO_VERSION=' .env | cut -d= -f2 || true)" CURRENT="${CURRENT:-4.4}" if [[ "$CURRENT" == "$TARGET" ]]; then echo "MongoDB ist bereits auf $TARGET gepinnt — nichts zu tun." exit 0 fi if [[ ! -d "$DB_DATA" ]] || [[ -z "$(ls -A "$DB_DATA" 2>/dev/null)" ]]; then echo "Keine bestehende Datenbank gefunden — einfach ./start.sh ausführen," echo "das richtet direkt mongo:$TARGET ein." exit 1 fi echo "==> Migriere von mongo:$CURRENT auf mongo:$TARGET" # ---------- 3. Sicherheits-Backup ---------- echo "==> Komplett-Backup vor der Migration..." ./backup.sh --full # ---------- 4. Stack stoppen ---------- echo "==> Container stoppen..." docker-compose down docker rm -f "$TMP_NAME" >/dev/null 2>&1 || true # Hilfsfunktionen: temporären mongod starten/abfragen/stoppen mongo_eval() { docker exec "$TMP_NAME" sh -c \ 'if command -v mongosh >/dev/null; then mongosh --quiet --eval "$0"; else mongo --quiet --eval "$0"; fi' \ "$1" } wait_for_mongo() { local i for i in $(seq 1 60); do if mongo_eval 'db.adminCommand({ping:1}).ok' >/dev/null 2>&1; then return 0; fi sleep 2 done echo "FEHLER: mongod wurde nicht rechtzeitig bereit."; return 1 } run_step() { local version="$1" echo "==> Schritt: mongo:$version starten..." docker run -d --name "$TMP_NAME" -v "$DB_DATA":/data/db "mongo:$version" >/dev/null wait_for_mongo local fcv_cmd if [[ "$version" == "7.0" ]]; then fcv_cmd="db.adminCommand({setFeatureCompatibilityVersion: \"$version\", confirm: true})" else fcv_cmd="db.adminCommand({setFeatureCompatibilityVersion: \"$version\"})" fi echo " featureCompatibilityVersion -> $version" mongo_eval "$fcv_cmd" >/dev/null docker stop "$TMP_NAME" >/dev/null docker rm "$TMP_NAME" >/dev/null echo " Schritt $version abgeschlossen." } # ---------- 5. Schrittweise migrieren ---------- started=false for step in "${MIGRATION_PATH[@]}"; do # Schritte unterhalb der aktuellen Version überspringen (z.B. Start bei 5.0) if [[ "$started" == false ]]; then if [[ "$(printf '%s\n' "$CURRENT" "$step" | sort -V | head -1)" == "$CURRENT" && "$CURRENT" != "$step" ]]; then started=true else continue fi fi run_step "$step" done # ---------- 6. Pin aktualisieren und Stack starten ---------- sed -i "s/^MONGO_VERSION=.*/MONGO_VERSION=$TARGET/" .env echo "==> MONGO_VERSION=$TARGET in .env gesetzt." echo "==> Stack wieder starten..." docker-compose pull unifi-db docker-compose up -d echo "" echo "Migration abgeschlossen. Prüfen mit:" echo " docker exec unifi-db mongosh --quiet --eval 'db.version()'" echo " curl -sk https://localhost:8443/status" echo "Das Sicherheits-Backup liegt in ./backups/ und kann bei Problemen" echo "mit ./restore.sh wiederhergestellt werden."