snapshot: preserve backup UX, remote target setup, and docs updates

This commit is contained in:
Md Bayazid Bostame
2026-03-26 01:53:44 +01:00
parent 2a372fdb15
commit 438334bd92
26 changed files with 1737 additions and 383 deletions

36
scripts/backup_create.sh Normal file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
set -a
. ./.env
set +a
timestamp="$(date +"%Y%m%d_%H%M%S")"
backup_dir="${1:-$ROOT_DIR/backend/backups/backup_${timestamp}}"
mkdir -p "$backup_dir"
db_dump_path="$backup_dir/db.dump"
media_archive_path="$backup_dir/media.tar.gz"
meta_path="$backup_dir/backup_meta.env"
checksums_path="$backup_dir/SHA256SUMS"
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' pg_dump -U '$POSTGRES_USER' -d '$POSTGRES_DB' -Fc --no-owner --no-privileges" > "$db_dump_path"
tar -C "$ROOT_DIR/backend" -czf "$media_archive_path" media
cat > "$meta_path" <<EOF
BACKUP_CREATED_AT=$timestamp
POSTGRES_DB=$POSTGRES_DB
POSTGRES_USER=$POSTGRES_USER
DB_DUMP_FILE=$(basename "$db_dump_path")
MEDIA_ARCHIVE_FILE=$(basename "$media_archive_path")
EOF
(
cd "$backup_dir"
shasum -a 256 "$(basename "$db_dump_path")" "$(basename "$media_archive_path")" > "$checksums_path"
)
printf '%s\n' "$backup_dir"

35
scripts/backup_restore.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 2 || "$1" != "--yes-restore" ]]; then
echo "Usage: $0 --yes-restore <backup_dir>" >&2
exit 1
fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
backup_dir="$2"
db_dump_path="$backup_dir/db.dump"
media_archive_path="$backup_dir/media.tar.gz"
if [[ ! -f "$db_dump_path" || ! -f "$media_archive_path" ]]; then
echo "Backup files missing in $backup_dir" >&2
exit 1
fi
set -a
. ./.env
set +a
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d postgres -c \"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$POSTGRES_DB' AND pid <> pg_backend_pid();\""
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d postgres -c \"DROP DATABASE IF EXISTS \\\"$POSTGRES_DB\\\";\""
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d postgres -c \"CREATE DATABASE \\\"$POSTGRES_DB\\\";\""
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' pg_restore -U '$POSTGRES_USER' -d '$POSTGRES_DB' --no-owner --no-privileges" < "$db_dump_path"
rm -rf "$ROOT_DIR/backend/media"
mkdir -p "$ROOT_DIR/backend"
tar -C "$ROOT_DIR/backend" -xzf "$media_archive_path"
echo "Restore completed from $backup_dir"

55
scripts/backup_verify.sh Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <backup_dir>" >&2
exit 1
fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
backup_dir="$1"
db_dump_path="$backup_dir/db.dump"
media_archive_path="$backup_dir/media.tar.gz"
if [[ ! -f "$db_dump_path" || ! -f "$media_archive_path" ]]; then
echo "Backup files missing in $backup_dir" >&2
exit 1
fi
set -a
. ./.env
set +a
verify_db="${POSTGRES_DB}_verify_$(date +%s)"
verify_media_dir="$(mktemp -d /tmp/tubco_backup_verify_media.XXXXXX)"
cleanup() {
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d postgres -c \"DROP DATABASE IF EXISTS \\\"$verify_db\\\";\"" >/dev/null 2>&1 || true
chmod -R u+rwx "$verify_media_dir" >/dev/null 2>&1 || true
rm -rf "$verify_media_dir"
}
trap cleanup EXIT
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d postgres -c \"CREATE DATABASE \\\"$verify_db\\\";\""
docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' pg_restore -U '$POSTGRES_USER' -d '$verify_db' --no-owner --no-privileges" < "$db_dump_path"
table_count="$(docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d '$verify_db' -t -A -c \"SELECT COUNT(*) FROM pg_tables WHERE schemaname='public';\"")"
onboarding_count="$(docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d '$verify_db' -t -A -c \"SELECT COUNT(*) FROM workflows_onboardingrequest;\"")"
offboarding_count="$(docker compose exec -T db sh -lc "PGPASSWORD='$POSTGRES_PASSWORD' psql -U '$POSTGRES_USER' -d '$verify_db' -t -A -c \"SELECT COUNT(*) FROM workflows_offboardingrequest;\"")"
tar -C "$verify_media_dir" --no-same-owner --no-same-permissions -xzf "$media_archive_path"
if [[ ! -d "$verify_media_dir/media" ]]; then
echo "Media restore verification failed: extracted media directory missing" >&2
exit 1
fi
media_file_count="$(find "$verify_media_dir/media" -type f | wc -l | tr -d ' ')"
printf 'Verified backup: %s\n' "$backup_dir"
printf 'Restore DB: %s\n' "$verify_db"
printf 'Public tables: %s\n' "$table_count"
printf 'Onboarding rows: %s\n' "$onboarding_count"
printf 'Offboarding rows: %s\n' "$offboarding_count"
printf 'Media files: %s\n' "$media_file_count"