This commit is contained in:
gpatruno
2026-07-18 16:26:08 +02:00
parent 49c444e8b9
commit 2614d679c8
85 changed files with 8074 additions and 710 deletions
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
# Export CaseGambling database (+ uploads) FROM Docker (production).
# Run this on the prod server next to docker-compose.yml.
#
# Usage:
# ./scripts/docker-db-export.sh
# ./scripts/docker-db-export.sh ./backups/my-backup
#
# Output:
# backups/casegambling-YYYYMMDD-HHMMSS/
# prod.db (+ optional -wal/-shm)
# uploads/
# manifest.txt
# backups/casegambling-YYYYMMDD-HHMMSS.tar.gz
#
# Then copy the .tar.gz to your machine and import locally:
# ./scripts/local-db-import.sh ./backups/casegambling-….tar.gz
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [[ -f "$SCRIPT_DIR/../docker-compose.yml" ]]; then
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
elif [[ -f "$SCRIPT_DIR/docker-compose.yml" ]]; then
ROOT="$SCRIPT_DIR"
else
echo "Error: docker-compose.yml not found near $SCRIPT_DIR" >&2
exit 1
fi
cd "$ROOT"
ENV_FILE="${ENV_FILE:-.env.prod}"
COMPOSE=(docker compose)
if [[ -f "$ENV_FILE" ]]; then
COMPOSE=(docker compose --env-file "$ENV_FILE")
fi
SERVICE="${SERVICE:-casegambling}"
STAMP="$(date +%Y%m%d-%H%M%S)"
OUT="${1:-$ROOT/backups/casegambling-$STAMP}"
if ! command -v docker >/dev/null 2>&1; then
echo "Error: docker not found" >&2
exit 1
fi
if ! "${COMPOSE[@]}" ps -q "$SERVICE" >/dev/null 2>&1; then
echo "Error: compose service '$SERVICE' not found" >&2
echo "Tip: run from the folder that has docker-compose.yml" >&2
exit 1
fi
mkdir -p "$OUT"
echo "==> Exporting Docker database → $OUT/prod.db"
echo " service: $SERVICE · volume path: /data/prod.db"
TMP_UPLOADS="$(mktemp -d)"
cleanup() {
rm -rf "$TMP_UPLOADS"
}
trap cleanup EXIT
WAS_RUNNING=0
if [[ -n "$("${COMPOSE[@]}" ps -q --status running "$SERVICE" 2>/dev/null || true)" ]]; then
WAS_RUNNING=1
fi
# Prefer a consistent SQLite snapshot inside a running container
if [[ "$WAS_RUNNING" -eq 1 ]] \
&& "${COMPOSE[@]}" exec -T "$SERVICE" sh -c 'command -v sqlite3 >/dev/null && test -f /data/prod.db'; then
"${COMPOSE[@]}" exec -T "$SERVICE" sh -c "sqlite3 /data/prod.db \".backup '/tmp/prod-export.db'\""
"${COMPOSE[@]}" cp "$SERVICE:/tmp/prod-export.db" "$OUT/prod.db"
"${COMPOSE[@]}" exec -T "$SERVICE" rm -f /tmp/prod-export.db >/dev/null 2>&1 || true
else
# Safe file copy: stop if running so WAL is flushed
if [[ "$WAS_RUNNING" -eq 1 ]]; then
echo "==> Stopping $SERVICE for a consistent copy"
"${COMPOSE[@]}" stop "$SERVICE" >/dev/null
fi
"${COMPOSE[@]}" cp "$SERVICE:/data/prod.db" "$OUT/prod.db"
"${COMPOSE[@]}" cp "$SERVICE:/data/prod.db-wal" "$OUT/prod.db-wal" 2>/dev/null || true
"${COMPOSE[@]}" cp "$SERVICE:/data/prod.db-shm" "$OUT/prod.db-shm" 2>/dev/null || true
if [[ "$WAS_RUNNING" -eq 1 ]]; then
echo "==> Starting $SERVICE"
"${COMPOSE[@]}" start "$SERVICE" >/dev/null 2>&1 || "${COMPOSE[@]}" up -d "$SERVICE" >/dev/null
fi
fi
# Also write as dev.db so local import can use either name
cp -f "$OUT/prod.db" "$OUT/dev.db"
[[ -f "$OUT/prod.db-wal" ]] && cp -f "$OUT/prod.db-wal" "$OUT/dev.db-wal"
[[ -f "$OUT/prod.db-shm" ]] && cp -f "$OUT/prod.db-shm" "$OUT/dev.db-shm"
echo "==> Exporting Docker uploads → $OUT/uploads"
mkdir -p "$OUT/uploads"
if "${COMPOSE[@]}" cp "$SERVICE:/app/uploads/." "$TMP_UPLOADS/" 2>/dev/null; then
cp -a "$TMP_UPLOADS"/. "$OUT/uploads/" 2>/dev/null || true
else
echo " (no uploads or empty volume)"
fi
{
echo "exported_at=$STAMP"
echo "source=docker"
echo "service=$SERVICE"
echo "database=prod.db"
echo "uploads=uploads/"
} > "$OUT/manifest.txt"
TAR="$OUT.tar.gz"
tar -czf "$TAR" -C "$(dirname "$OUT")" "$(basename "$OUT")"
DB_SIZE="$(du -h "$OUT/prod.db" | awk '{print $1}')"
UPLOAD_COUNT="$(find "$OUT/uploads" -type f 2>/dev/null | wc -l | tr -d ' ')"
echo "==> Archive: $TAR"
echo " db size: $DB_SIZE · uploads files: $UPLOAD_COUNT"
echo "==> Done. On your laptop:"
echo " scp user@prod:$TAR ./backups/"
echo " ./scripts/local-db-import.sh ./backups/$(basename "$TAR")"