125 lines
4.5 KiB
Bash
125 lines
4.5 KiB
Bash
#!/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."
|