Skip to content

Commit f7b5b46

Browse files
authored
Merge pull request #247 from coder13/agent/live-mongo-backup-restore-rehearsal
Run a live MongoDB restore rehearsal
2 parents 2cbe53e + 066422e commit f7b5b46

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- name: Rehearse MongoDB backup and restore scripts
2828
run: scripts/test-mongo-backup-restore.sh
2929

30+
- name: Rehearse a live MongoDB backup and restore
31+
run: scripts/test-mongo-backup-restore-live.sh
32+
3033
server:
3134
name: Server lint and unit tests
3235
runs-on: ubuntu-latest

docs/operations.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,15 @@ The deploy script can be tested without production access:
132132
scripts/test-deploy-classifier.sh
133133
scripts/test-deploy.sh
134134
scripts/test-mongo-backup-restore.sh
135+
scripts/test-mongo-backup-restore-live.sh
135136
scripts/classify-deploy-target.sh client/src/components/App.jsx
136137
```
137138

139+
The live MongoDB rehearsal starts two disposable `mongo:7` containers on an
140+
isolated Docker network, writes only a synthetic attempt, restores it with
141+
`--drop`, verifies it, and removes the containers and network on exit. It never
142+
connects to the configured production or development database.
143+
138144
## Verification And Monitoring
139145

140146
After deployment, verify:
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
TEST_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/letscube-mongo-live-rehearsal.XXXXXX")"
5+
NETWORK="letscube-mongo-rehearsal-$RANDOM-$$"
6+
SOURCE="${NETWORK}-source"
7+
TARGET="${NETWORK}-target"
8+
ARCHIVE="$TEST_ROOT/backup.archive.gz"
9+
10+
cleanup() {
11+
docker rm -f "$SOURCE" "$TARGET" >/dev/null 2>&1 || true
12+
docker network rm "$NETWORK" >/dev/null 2>&1 || true
13+
rm -rf -- "$TEST_ROOT"
14+
}
15+
16+
trap cleanup EXIT
17+
18+
wait_for_mongo() {
19+
local container="$1"
20+
local attempt
21+
22+
for attempt in {1..30}; do
23+
if docker exec "$container" mongosh --quiet --eval 'db.runCommand({ ping: 1 }).ok' \
24+
| grep -qx '1'; then
25+
return
26+
fi
27+
28+
sleep 1
29+
done
30+
31+
echo "MongoDB did not become ready: $container" >&2
32+
docker logs "$container" >&2 || true
33+
exit 1
34+
}
35+
36+
docker network create "$NETWORK" >/dev/null
37+
docker run -d --rm --name "$SOURCE" --network "$NETWORK" mongo:7.0 >/dev/null
38+
docker run -d --rm --name "$TARGET" --network "$NETWORK" mongo:7.0 >/dev/null
39+
40+
wait_for_mongo "$SOURCE"
41+
wait_for_mongo "$TARGET"
42+
43+
docker exec "$SOURCE" mongosh rehearsal --quiet --eval \
44+
'db.attempts.insertOne({ ordinal: 1, scramble: "synthetic", solveMs: 12345 })' >/dev/null
45+
docker exec "$TARGET" mongosh rehearsal --quiet --eval \
46+
'db.attempts.insertOne({ stale: true })' >/dev/null
47+
48+
docker exec "$SOURCE" mongodump \
49+
--uri 'mongodb://localhost:27017/rehearsal' \
50+
--archive --gzip > "$ARCHIVE"
51+
docker exec -i "$TARGET" mongorestore \
52+
--uri 'mongodb://localhost:27017/rehearsal' \
53+
--drop --archive --gzip < "$ARCHIVE"
54+
55+
record_count="$(docker exec "$TARGET" mongosh rehearsal --quiet --eval 'db.attempts.countDocuments({})')"
56+
scramble="$(docker exec "$TARGET" mongosh rehearsal --quiet --eval 'db.attempts.findOne().scramble')"
57+
58+
if [ "$record_count" != '1' ] || [ "$scramble" != 'synthetic' ]; then
59+
echo 'MongoDB backup/restore rehearsal did not preserve the synthetic attempt.' >&2
60+
exit 1
61+
fi
62+
63+
echo 'Live MongoDB backup and restore rehearsal passed.'

0 commit comments

Comments
 (0)