#!/usr/bin/env bash
# backup/stages/pg-dump.sh
# pg_dump each logical database running in the compose `postgres` service.
# Output is written compressed to DEST_DIR/<db>.sql.zst then symlinked
# into ../latest/pg/.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
. "${HERE}/../../scripts/lib/log.sh"
DEST_ROOT="${DEST_ROOT:-/srv/homelab/backup/snapshots/pg}"
LATEST="${LATEST:-/srv/homelab/backup/latest/pg}"
TS="$(date +%Y%m%dT%H%M%S)"
DEST="${DEST_ROOT}/${TS}"
CONTAINER="${CONTAINER:-homelab-postgres-1}"
PG_USER="${PG_USER:-postgres}"
install -d "${DEST}"
list_dbs() {
docker exec -u "${PG_USER}" "${CONTAINER}" \
psql -Atqc "SELECT datname FROM pg_database WHERE datistemplate = false AND datname <> 'postgres'"
}
dump_one() {
local db="$1"
local out="${DEST}/${db}.sql.zst"
log_info "pg_dump ${db}"
if docker exec -u "${PG_USER}" "${CONTAINER}" \
pg_dump --format=plain --no-owner --no-privileges "${db}" \
| zstd -q -T0 -3 -o "${out}"; then
return 0
fi
log_err "pg_dump failed for ${db}"
return 1
}
main() {
if ! docker inspect "${CONTAINER}" >/dev/null 2>&1; then
log_err "container ${CONTAINER} not running"
exit 2
fi
local failed=0
while IFS= read -r db; do
[[ -z "${db}" ]] && continue
dump_one "${db}" || failed=$((failed + 1))
done < <(list_dbs)
if (( failed > 0 )); then
exit 1
fi
install -d "$(dirname "${LATEST}")"
rm -f "${LATEST}"
ln -s "${DEST}" "${LATEST}"
log_info "latest -> ${DEST}"
}
main "$@"