#!/usr/bin/env bash # Runs inside the migration container. # Copies all collections + indexes from $SRC_DB to $DST_DB, # verifies document counts, then optionally drops the source. set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[migrate]${NC} $*"; } warn() { echo -e "${YELLOW}[migrate]${NC} $*"; } die() { echo -e "${RED}[migrate]${NC} $*" >&2; exit 1; } MONGO_HOST="${MONGO_HOST:-mongo}" MONGO_PORT="${MONGO_PORT:-27017}" SRC_DB="${SRC_DB:-keymanager}" DST_DB="${DST_DB:-vantage}" DROP_SRC="${DROP_SRC:-false}" MONGO_URI="mongodb://${MONGO_HOST}:${MONGO_PORT}" mongosh_eval() { local db="$1"; local script="$2" mongosh --quiet "${MONGO_URI}/${db}" --eval "$script" } # --------------------------------------------------------------------------- # 1. Wait for MongoDB to be reachable # --------------------------------------------------------------------------- info "Waiting for MongoDB at ${MONGO_HOST}:${MONGO_PORT}..." for i in $(seq 1 30); do mongosh --quiet "${MONGO_URI}/admin" --eval "db.adminCommand('ping')" >/dev/null 2>&1 && break [ "$i" -eq 30 ] && die "MongoDB not reachable after 30 attempts." sleep 2 done info "MongoDB is ready." # --------------------------------------------------------------------------- # 2. Check source database # --------------------------------------------------------------------------- SRC_COLLECTIONS=$(mongosh_eval admin " const names = db.getSiblingDB('${SRC_DB}').getCollectionNames(); print(names.join(',')); ") if [ -z "$SRC_COLLECTIONS" ] || [ "$SRC_COLLECTIONS" = "," ]; then warn "Source database '${SRC_DB}' has no collections — nothing to migrate." warn "If this is a fresh deployment, '${DST_DB}' will be created automatically." exit 0 fi info "Collections in '${SRC_DB}': ${SRC_COLLECTIONS}" # --------------------------------------------------------------------------- # 3. Copy all collections via \$out # --------------------------------------------------------------------------- info "Copying collections from '${SRC_DB}' to '${DST_DB}'..." mongosh_eval admin " const src = db.getSiblingDB('${SRC_DB}'); const cols = src.getCollectionNames(); cols.forEach(function(name) { src[name].aggregate([{ \\\$out: { db: '${DST_DB}', coll: name } }]); print('Copied: ' + name); }); " # --------------------------------------------------------------------------- # 4. Recreate indexes # --------------------------------------------------------------------------- info "Recreating indexes in '${DST_DB}'..." mongosh_eval admin " const src = db.getSiblingDB('${SRC_DB}'); const dst = db.getSiblingDB('${DST_DB}'); src.getCollectionNames().forEach(function(col) { src[col].getIndexes().forEach(function(idx) { if (idx.name === '_id_') return; const opts = { name: idx.name }; if (idx.unique) opts.unique = true; if (idx.sparse) opts.sparse = true; if (idx.expireAfterSeconds !== undefined) opts.expireAfterSeconds = idx.expireAfterSeconds; try { dst[col].createIndex(idx.key, opts); print('Index: ' + col + '.' + idx.name); } catch(e) { print('Skipped index ' + idx.name + ' on ' + col + ': ' + e.message); } }); }); " # --------------------------------------------------------------------------- # 5. Verify document counts # --------------------------------------------------------------------------- info "Verifying document counts..." MISMATCH=0 IFS=',' read -ra COLS <<< "$SRC_COLLECTIONS" for col in "${COLS[@]}"; do [ -z "$col" ] && continue SRC_N=$(mongosh_eval "$SRC_DB" "print(db['${col}'].countDocuments())") DST_N=$(mongosh_eval "$DST_DB" "print(db['${col}'].countDocuments())") if [ "$SRC_N" = "$DST_N" ]; then info " ${col}: ${SRC_N} docs OK" else warn " ${col}: src=${SRC_N} dst=${DST_N} MISMATCH" MISMATCH=1 fi done [ "$MISMATCH" -eq 1 ] && die "Count mismatch — source database NOT dropped. Investigate and re-run." # --------------------------------------------------------------------------- # 6. Optionally drop source database # --------------------------------------------------------------------------- if [ "$DROP_SRC" = "true" ]; then info "Dropping source database '${SRC_DB}'..." mongosh_eval admin "db.getSiblingDB('${SRC_DB}').dropDatabase(); print('Dropped.');" info "Dropped '${SRC_DB}'." else warn "Source database '${SRC_DB}' kept. Set DROP_SRC=true to drop it automatically." fi info "Migration complete."