who_need_help/scripts/restore-drill-compose.sh

170 lines
3.9 KiB
Bash
Executable File

#!/bin/sh
set -eu
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$ROOT"
if [ "$#" -ne 1 ]; then
echo "Usage: $0 PATH_TO_CUSTOM_FORMAT_DUMP" >&2
exit 1
fi
dump=$1
checksum="$dump.sha256"
if [ ! -f "$dump" ] || [ ! -s "$dump" ]; then
echo "Dump does not exist or is empty: $dump" >&2
exit 1
fi
if [ ! -f "$checksum" ]; then
echo "Checksum manifest is required: $checksum" >&2
exit 1
fi
if [ ! -f "$ROOT/.env" ]; then
echo "Missing $ROOT/.env." >&2
exit 1
fi
set -a
. "$ROOT/.env"
set +a
: "${POSTGRES_DB:?Set POSTGRES_DB in .env}"
: "${POSTGRES_USER:?Set POSTGRES_USER in .env}"
: "${DATABASE_URL:?Set DATABASE_URL in .env}"
dump_dir=$(CDPATH= cd -- "$(dirname -- "$dump")" && pwd)
dump_name=$(basename -- "$dump")
(
cd "$dump_dir"
sha256sum --check --status "$(basename -- "$checksum")"
)
docker compose exec -T db pg_restore --list <"$dump" >/dev/null
drill_db="who_need_help_restore_drill_$(date -u +%Y%m%d%H%M%S)_$$"
created=false
cleanup() {
if [ "$created" = true ]; then
docker compose exec -T db \
dropdb --username "$POSTGRES_USER" --if-exists "$drill_db" >/dev/null
fi
}
trap cleanup EXIT HUP INT TERM
docker compose exec -T db \
createdb \
--username "$POSTGRES_USER" \
--template template0 \
"$drill_db"
created=true
docker compose exec -T db \
pg_restore \
--username "$POSTGRES_USER" \
--dbname "$drill_db" \
--exit-on-error \
--no-owner \
--no-privileges <"$dump"
tables=$(
docker compose exec -T db \
psql --username "$POSTGRES_USER" --dbname "$drill_db" --tuples-only --no-align \
--command "
SELECT tablename
FROM pg_tables
WHERE schemaname = 'public'
AND tablename <> 'spatial_ref_sys'
ORDER BY tablename;
"
)
table_count=0
total_rows=0
for table in $tables; do
restored_count=$(
docker compose exec -T db \
psql --username "$POSTGRES_USER" --dbname "$drill_db" --tuples-only --no-align \
--command "SELECT count(*) FROM \"$table\";"
)
table_count=$((table_count + 1))
total_rows=$((total_rows + restored_count))
done
if [ "$table_count" -eq 0 ]; then
echo "The restored database contains no public application tables." >&2
exit 1
fi
postgis_version=$(
docker compose exec -T db \
psql --username "$POSTGRES_USER" --dbname "$drill_db" --tuples-only --no-align \
--command "SELECT PostGIS_Lib_Version();"
)
case "$DATABASE_URL" in
*\?*)
database_base=${DATABASE_URL%%\?*}
database_query="?${DATABASE_URL#*\?}"
;;
*)
database_base=$DATABASE_URL
database_query=
;;
esac
database_prefix=${database_base%/*}
if [ "$database_prefix" = "$database_base" ]; then
echo "Could not derive the temporary drill DATABASE_URL." >&2
exit 1
fi
drill_database_url="$database_prefix/$drill_db$database_query"
docker compose run --rm --no-deps \
--env APP_ROLE=migrate \
--env "DATABASE_URL=$drill_database_url" \
migrate /app/bin/migrate
docker compose run --rm --no-deps \
--env APP_ROLE=migrate \
--env "DATABASE_URL=$drill_database_url" \
migrate /app/bin/who_need_help eval 'WhoNeedHelp.Release.await_migrations()'
migration_count=$(
docker compose exec -T db \
psql --username "$POSTGRES_USER" --dbname "$drill_db" --tuples-only --no-align \
--command "SELECT count(*) FROM schema_migrations;"
)
docker compose exec -T db \
dropdb --username "$POSTGRES_USER" "$drill_db"
created=false
trap - EXIT HUP INT TERM
remaining=$(
docker compose exec -T db \
psql --username "$POSTGRES_USER" --dbname postgres --tuples-only --no-align \
--command "SELECT count(*) FROM pg_database WHERE datname = '$drill_db';"
)
if [ "$remaining" != "0" ]; then
echo "Restore drill database was not removed: $drill_db" >&2
exit 1
fi
echo "Restore drill passed for: $dump_name"
echo "Readable public tables: $table_count"
echo "Restored rows read: $total_rows"
echo "Applied migrations: $migration_count"
echo "PostGIS library: $postgis_version"
echo "Temporary database removed: $drill_db"