Files
home-infra/scripts/deploy-nextcloud.sh
T
a.zubarev bdacca1931
Nextcloud CI/CD / Deploy Nextcloud (push) Failing after 2s
Обновить scripts/deploy-nextcloud.sh
2026-09-30 12:53:21 +03:00

1253 lines
26 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
# ============================================================
# Configuration
# ============================================================
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SRC="${ROOT}/stacks/nextcloud"
LIVE="/srv/nfs/infra/nextcloud"
ENV_FILE="${LIVE}/.env"
BACKUP_ROOT="/srv/nfs/infra/.deploy-backups/nextcloud"
BACKUP_KEEP=3
STAMP="$(date '+%Y%m%d-%H%M%S')"
BACKUP_DIR="${BACKUP_ROOT}/${STAMP}"
DB_BACKUP_DIR="${BACKUP_DIR}/database"
DB_BACKUP_FILE="${DB_BACKUP_DIR}/nextcloud.dump"
# ============================================================
# Helpers
# ============================================================
log()
{
echo
echo "============================================================"
echo "$*"
echo "============================================================"
}
fail()
{
echo
echo "ERROR: $*" >&2
exit 1
}
on_error()
{
rc=$?
trap - ERR
echo
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo " Nextcloud deployment FAILED"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
if [[ -d "${BACKUP_DIR}" ]]; then
echo
echo "Pre-upgrade backup:"
echo " ${BACKUP_DIR}"
fi
echo
echo "Automatic rollback is intentionally NOT performed."
echo "The Nextcloud database schema may already have been modified."
echo "Use the pre-upgrade PostgreSQL dump if a rollback is required."
exit "${rc}"
}
cleanup_old_backups()
{
echo
echo "--- Backup retention ---"
echo "Keeping last ${BACKUP_KEEP} pre-upgrade backups."
mkdir -p "${BACKUP_ROOT}"
mapfile -t BACKUPS < <(
find "${BACKUP_ROOT}" \
-mindepth 1 \
-maxdepth 1 \
-type d \
-printf '%f\n' |
grep -E '^[0-9]{8}-[0-9]{6}$' |
sort -r
)
if (( ${#BACKUPS[@]} <= BACKUP_KEEP )); then
echo "Current backup count: ${#BACKUPS[@]}"
echo "Nothing to delete."
return 0
fi
for BACKUP_NAME in "${BACKUPS[@]:${BACKUP_KEEP}}"
do
OLD_BACKUP="${BACKUP_ROOT}/${BACKUP_NAME}"
echo
echo "Removing old backup:"
echo " ${OLD_BACKUP}"
rm -rf -- "${OLD_BACKUP}"
done
}
version_less_than()
{
local A="$1"
local B="$2"
[[ "${A}" == "${B}" ]] && return 1
[[ "$(
printf '%s\n%s\n' "${A}" "${B}" |
sort -V |
head -n1
)" == "${A}" ]]
}
trap on_error ERR
# ============================================================
# Required commands
# ============================================================
log "Pre-flight checks"
for CMD in \
docker \
psql \
pg_dump \
pg_restore \
sha256sum \
sort \
grep \
find
do
command -v "${CMD}" >/dev/null 2>&1 || \
fail "Required command not found: ${CMD}"
done
docker compose version >/dev/null 2>&1 || \
fail "Docker Compose plugin is not available"
# ============================================================
# Required files
# ============================================================
[[ -f "${SRC}/docker-compose.yml" ]] || \
fail "${SRC}/docker-compose.yml not found"
[[ -f "${LIVE}/docker-compose.yml" ]] || \
fail "${LIVE}/docker-compose.yml not found"
[[ -f "${ENV_FILE}" ]] || \
fail "${ENV_FILE} not found"
# ============================================================
# Backup directory access
# ============================================================
mkdir -p "${BACKUP_ROOT}"
[[ -w "${BACKUP_ROOT}" ]] || \
fail "${BACKUP_ROOT} is not writable"
# ============================================================
# Load PostgreSQL settings
#
# .env must be shell-compatible.
#
# Example:
#
# POSTGRES_HOST=192.168.1.20
# POSTGRES_DB=nextcloud
# POSTGRES_USER=nextcloud
# POSTGRES_PASSWORD='complex@password'
# ============================================================
set -a
# shellcheck disable=SC1090
source "${ENV_FILE}"
set +a
: "${POSTGRES_HOST:?POSTGRES_HOST not defined}"
: "${POSTGRES_DB:?POSTGRES_DB not defined}"
: "${POSTGRES_USER:?POSTGRES_USER not defined}"
: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not defined}"
export PGPASSWORD="${POSTGRES_PASSWORD}"
export PGCONNECT_TIMEOUT=10
# ============================================================
# Validate requested Compose
# ============================================================
log "Validate Docker Compose"
docker compose \
-f "${SRC}/docker-compose.yml" \
config >/dev/null
echo "Docker Compose configuration is valid."
# ============================================================
# Detect requested Nextcloud image
#
# nextcloud and cron MUST use exactly the same image.
# ============================================================
log "Detect requested Nextcloud image"
mapfile -t NEXTCLOUD_IMAGES < <(
docker compose \
-f "${SRC}/docker-compose.yml" \
config --images |
grep '^nextcloud:' |
sort -u
)
if [[ "${#NEXTCLOUD_IMAGES[@]}" -ne 1 ]]; then
echo "Detected Nextcloud images:"
if (( ${#NEXTCLOUD_IMAGES[@]} > 0 )); then
printf ' %s\n' "${NEXTCLOUD_IMAGES[@]}"
else
echo " none"
fi
fail "Services nextcloud and cron must use exactly the same Nextcloud image"
fi
NEW_IMAGE="${NEXTCLOUD_IMAGES[0]}"
echo "Requested image:"
echo " ${NEW_IMAGE}"
# ============================================================
# Current Nextcloud container
# ============================================================
docker inspect nextcloud >/dev/null 2>&1 || \
fail "Current Nextcloud container does not exist"
CURRENT_RUNNING="$(
docker inspect \
-f '{{.State.Running}}' \
nextcloud
)"
[[ "${CURRENT_RUNNING}" == "true" ]] || \
fail "Current Nextcloud container is not running"
OLD_IMAGE="$(
docker inspect \
-f '{{.Config.Image}}' \
nextcloud
)"
# ============================================================
# Detect current Nextcloud status/version
#
# Use OCC instead of reading version.php directly.
# OCC is the supported machine-readable interface and also
# verifies that the currently running installation can load.
# ============================================================
log "Detect current Nextcloud version"
set +e
CURRENT_STATUS_JSON="$(
docker exec \
-u www-data \
nextcloud \
php occ status \
--output=json \
2>&1
)"
CURRENT_STATUS_RC=$?
set -e
if [[ "${CURRENT_STATUS_RC}" -ne 0 ]]
then
echo
echo "--- OCC status output ---"
echo "${CURRENT_STATUS_JSON}"
fail \
"Could not get current Nextcloud status (exit code ${CURRENT_STATUS_RC})"
fi
CURRENT_NC_VERSION="$(
printf '%s\n' "${CURRENT_STATUS_JSON}" |
sed -nE \
's/.*"versionstring"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' |
head -n1
)"
[[ -n "${CURRENT_NC_VERSION}" ]] || {
echo
echo "OCC output:"
echo "${CURRENT_STATUS_JSON}"
fail "Could not determine current Nextcloud version"
}
echo "Current image:"
echo " ${OLD_IMAGE}"
echo "Current Nextcloud version:"
echo " ${CURRENT_NC_VERSION}"
# ============================================================
# Pull target Nextcloud image
#
# This does not modify the running container.
# ============================================================
log "Pull target Nextcloud image"
docker pull "${NEW_IMAGE}"
# ============================================================
# Determine actual Nextcloud version in target image
# ============================================================
log "Detect target Nextcloud version"
TARGET_NC_VERSION="$(
docker run \
--rm \
--entrypoint php \
"${NEW_IMAGE}" \
-r '
require "/usr/src/nextcloud/version.php";
echo implode(".", $OC_Version);
'
)"
[[ -n "${TARGET_NC_VERSION}" ]] || \
fail "Could not determine target Nextcloud version"
echo "Target Docker image:"
echo " ${NEW_IMAGE}"
echo "Target Nextcloud version:"
echo " ${TARGET_NC_VERSION}"
# ============================================================
# Version safety checks
# ============================================================
log "Validate version transition"
# ------------------------------------------------------------
# Downgrade protection
# ------------------------------------------------------------
if version_less_than \
"${TARGET_NC_VERSION}" \
"${CURRENT_NC_VERSION}"
then
fail \
"Nextcloud downgrade is not allowed: ${CURRENT_NC_VERSION} -> ${TARGET_NC_VERSION}"
fi
CURRENT_MAJOR="${CURRENT_NC_VERSION%%.*}"
TARGET_MAJOR="${TARGET_NC_VERSION%%.*}"
# ------------------------------------------------------------
# Prevent skipping major versions
# ------------------------------------------------------------
if (( TARGET_MAJOR > CURRENT_MAJOR + 1 ))
then
fail \
"Skipping Nextcloud major versions is forbidden: ${CURRENT_MAJOR} -> ${TARGET_MAJOR}"
fi
# ------------------------------------------------------------
# Determine whether actual Nextcloud version changed
# ------------------------------------------------------------
VERSION_CHANGED=false
if [[ "${CURRENT_NC_VERSION}" != "${TARGET_NC_VERSION}" ]]
then
VERSION_CHANGED=true
fi
echo "Current version: ${CURRENT_NC_VERSION}"
echo "Target version: ${TARGET_NC_VERSION}"
echo "Version changed: ${VERSION_CHANGED}"
# ============================================================
# Check current Nextcloud status
# ============================================================
log "Check current Nextcloud status"
CURRENT_STATUS="$(
docker exec \
-u www-data \
nextcloud \
php occ status
)"
echo "${CURRENT_STATUS}"
echo "${CURRENT_STATUS}" |
grep -Eq 'needsDbUpgrade:[[:space:]]*false' || \
fail "Current Nextcloud already requires a DB upgrade"
echo "${CURRENT_STATUS}" |
grep -Eq 'maintenance:[[:space:]]*false' || \
fail "Current Nextcloud is already in maintenance mode"
docker exec \
-u www-data \
nextcloud \
php occ status -e
# ============================================================
# PRE-UPGRADE BACKUP
#
# Created ONLY if actual Nextcloud version changes.
# ============================================================
if [[ "${VERSION_CHANGED}" == "true" ]]
then
log "Prepare Nextcloud pre-upgrade backup"
# --------------------------------------------------------
# Create backup directories
# --------------------------------------------------------
mkdir -p "${DB_BACKUP_DIR}"
# --------------------------------------------------------
# Save current Compose
#
# Do NOT use cp -a because this NFS does not support
# preserving all POSIX metadata.
# --------------------------------------------------------
echo
echo "--- Backup current docker-compose.yml ---"
cp \
"${LIVE}/docker-compose.yml" \
"${BACKUP_DIR}/docker-compose.yml"
# --------------------------------------------------------
# Save current Nextcloud status
# --------------------------------------------------------
printf '%s\n' "${CURRENT_STATUS}" \
> "${BACKUP_DIR}/nextcloud-status-before.txt"
# --------------------------------------------------------
# Save metadata
# --------------------------------------------------------
cat > "${BACKUP_DIR}/metadata.txt" <<EOF
timestamp=${STAMP}
current_image=${OLD_IMAGE}
target_image=${NEW_IMAGE}
current_nextcloud_version=${CURRENT_NC_VERSION}
target_nextcloud_version=${TARGET_NC_VERSION}
postgres_host=${POSTGRES_HOST}
postgres_database=${POSTGRES_DB}
postgres_user=${POSTGRES_USER}
EOF
# ========================================================
# PostgreSQL connectivity test
# ========================================================
echo
echo "--- Test PostgreSQL connection ---"
DB_TEST="$(
psql \
-h "${POSTGRES_HOST}" \
-U "${POSTGRES_USER}" \
-d "${POSTGRES_DB}" \
-Atqc 'SELECT 1;'
)"
[[ "${DB_TEST}" == "1" ]] || \
fail "Cannot connect to PostgreSQL"
echo "PostgreSQL connection successful."
# ========================================================
# PostgreSQL server/client compatibility
# ========================================================
echo
echo "--- PostgreSQL version check ---"
SERVER_VERSION="$(
psql \
-h "${POSTGRES_HOST}" \
-U "${POSTGRES_USER}" \
-d "${POSTGRES_DB}" \
-Atqc 'SHOW server_version;'
)"
[[ -n "${SERVER_VERSION}" ]] || \
fail "Could not determine PostgreSQL server version"
echo "${SERVER_VERSION}" \
> "${DB_BACKUP_DIR}/postgresql-version.txt"
SERVER_MAJOR="${SERVER_VERSION%%.*}"
PG_DUMP_VERSION="$(
pg_dump --version |
sed -E 's/.* ([0-9]+(\.[0-9]+)?).*/\1/'
)"
PG_DUMP_MAJOR="${PG_DUMP_VERSION%%.*}"
echo "PostgreSQL server:"
echo " ${SERVER_VERSION}"
echo "pg_dump client:"
echo " ${PG_DUMP_VERSION}"
if (( PG_DUMP_MAJOR < SERVER_MAJOR ))
then
fail \
"pg_dump ${PG_DUMP_VERSION} is older than PostgreSQL server ${SERVER_VERSION}"
fi
# ========================================================
# Database size
# ========================================================
echo
echo "--- Database size ---"
DB_SIZE="$(
psql \
-h "${POSTGRES_HOST}" \
-U "${POSTGRES_USER}" \
-d "${POSTGRES_DB}" \
-Atqc \
'SELECT pg_size_pretty(pg_database_size(current_database()));'
)"
echo "Database:"
echo " ${POSTGRES_DB}"
echo "Size:"
echo " ${DB_SIZE}"
# ========================================================
# PostgreSQL dump
# ========================================================
log "Create PostgreSQL backup"
pg_dump \
-h "${POSTGRES_HOST}" \
-U "${POSTGRES_USER}" \
-d "${POSTGRES_DB}" \
--format=custom \
--no-owner \
--no-privileges \
--file="${DB_BACKUP_FILE}"
[[ -s "${DB_BACKUP_FILE}" ]] || \
fail "PostgreSQL dump does not exist or is empty"
# ========================================================
# Validate PostgreSQL dump
# ========================================================
echo
echo "--- Validate PostgreSQL dump ---"
pg_restore \
--list \
"${DB_BACKUP_FILE}" \
> "${DB_BACKUP_DIR}/nextcloud.dump.list"
[[ -s "${DB_BACKUP_DIR}/nextcloud.dump.list" ]] || \
fail "pg_restore could not validate PostgreSQL dump"
# ========================================================
# SHA256 checksum
# ========================================================
echo
echo "--- Generate SHA256 ---"
(
cd "${DB_BACKUP_DIR}"
sha256sum \
nextcloud.dump \
> nextcloud.dump.sha256
)
sha256sum \
-c "${DB_BACKUP_DIR}/nextcloud.dump.sha256"
DB_BACKUP_SIZE="$(
du -h "${DB_BACKUP_FILE}" |
awk '{print $1}'
)"
echo
echo "PostgreSQL backup successful."
echo
echo "Backup directory:"
echo " ${BACKUP_DIR}"
echo
echo "Database dump:"
echo " ${DB_BACKUP_FILE}"
echo
echo "Dump size:"
echo " ${DB_BACKUP_SIZE}"
echo
echo "SHA256:"
cat "${DB_BACKUP_DIR}/nextcloud.dump.sha256"
# ========================================================
# Backup retention
#
# The new backup has already been successfully validated,
# so it is now safe to remove older backups.
# ========================================================
cleanup_old_backups
fi
# ============================================================
# Deploy requested Compose
#
# Production is not touched until pre-upgrade backup succeeds.
# ============================================================
log "Deploy docker-compose.yml"
cp \
"${SRC}/docker-compose.yml" \
"${LIVE}/docker-compose.yml"
cd "${LIVE}"
# ============================================================
# Pull all Compose images
# ============================================================
log "Pull Docker images"
docker compose pull
# ============================================================
# NEXTCLOUD VERSION UPGRADE
# ============================================================
if [[ "${VERSION_CHANGED}" == "true" ]]
then
log "Nextcloud upgrade ${CURRENT_NC_VERSION} -> ${TARGET_NC_VERSION}"
# ========================================================
# Stop cron during application/DB upgrade
# ========================================================
echo
echo "--- Stop Nextcloud cron ---"
docker compose stop cron || true
# ========================================================
# Timestamp used for startup log analysis
# ========================================================
UPGRADE_STARTED="$(
date -u '+%Y-%m-%dT%H:%M:%SZ'
)"
# ========================================================
# Recreate ONLY main Nextcloud container first
#
# Redis remains running.
# Cron remains stopped.
# ========================================================
echo
echo "--- Recreate Nextcloud container ---"
docker compose \
up -d \
--no-deps \
nextcloud
# ========================================================
# Wait for official Nextcloud Docker entrypoint
#
# The official image may execute occ upgrade automatically.
#
# 180 * 5 sec = 15 minutes maximum.
# ========================================================
log "Wait for Nextcloud initialization"
INITIALIZED=false
for _ in $(seq 1 180)
do
RUNNING="$(
docker inspect \
-f '{{.State.Running}}' \
nextcloud 2>/dev/null ||
echo false
)"
if [[ "${RUNNING}" != "true" ]]
then
echo
echo "--- Nextcloud container log ---"
docker logs \
--since "${UPGRADE_STARTED}" \
nextcloud || true
fail "Nextcloud container stopped during upgrade"
fi
STARTUP_LOG="$(
docker logs \
--since "${UPGRADE_STARTED}" \
nextcloud 2>&1 || true
)"
# Explicit failure from Nextcloud upgrade.
if echo "${STARTUP_LOG}" |
grep -q 'Update failed'
then
echo "${STARTUP_LOG}"
fail "Nextcloud automatic upgrade failed"
fi
# Standard completion marker of official image.
if echo "${STARTUP_LOG}" |
grep -q 'Initializing finished'
then
INITIALIZED=true
break
fi
sleep 5
done
if [[ "${INITIALIZED}" != "true" ]]
then
echo
echo "--- Nextcloud container log ---"
docker logs \
--since "${UPGRADE_STARTED}" \
nextcloud || true
fail "Timeout waiting for Nextcloud initialization"
fi
# ========================================================
# Capture entrypoint upgrade result
# ========================================================
log "Nextcloud startup upgrade output"
STARTUP_LOG="$(
docker logs \
--since "${UPGRADE_STARTED}" \
nextcloud 2>&1
)"
echo "${STARTUP_LOG}"
STARTUP_UPDATE_SUCCESS=false
if echo "${STARTUP_LOG}" |
grep -q 'Update successful'
then
STARTUP_UPDATE_SUCCESS=true
fi
echo
echo "Startup log contains 'Update successful':"
echo " ${STARTUP_UPDATE_SUCCESS}"
# ========================================================
# Explicit OCC upgrade
#
# If Docker entrypoint already performed the migration,
# occ upgrade can report that Nextcloud is already current.
# ========================================================
log "Run explicit occ upgrade"
set +e
OCC_UPGRADE_OUTPUT="$(
docker exec \
-u www-data \
nextcloud \
php occ upgrade 2>&1
)"
OCC_UPGRADE_RC=$?
set -e
echo "${OCC_UPGRADE_OUTPUT}"
if [[ "${OCC_UPGRADE_RC}" -ne 0 ]]
then
fail \
"Explicit occ upgrade returned exit code ${OCC_UPGRADE_RC}"
fi
EXPLICIT_UPDATE_SUCCESS=false
EXPLICIT_ALREADY_CURRENT=false
if echo "${OCC_UPGRADE_OUTPUT}" |
grep -q 'Update successful'
then
EXPLICIT_UPDATE_SUCCESS=true
fi
if echo "${OCC_UPGRADE_OUTPUT}" |
grep -Eqi \
'already.*(latest|up.?to.?date)|(is|already).*up.?to.?date'
then
EXPLICIT_ALREADY_CURRENT=true
fi
echo
echo "Explicit occ upgrade contains 'Update successful':"
echo " ${EXPLICIT_UPDATE_SUCCESS}"
echo "Explicit occ upgrade reports already current:"
echo " ${EXPLICIT_ALREADY_CURRENT}"
# ========================================================
# Require confirmed update
#
# Either:
# Docker entrypoint -> Update successful
#
# or:
# explicit occ upgrade -> Update successful
#
# ========================================================
if [[ "${STARTUP_UPDATE_SUCCESS}" != "true" ]] &&
[[ "${EXPLICIT_UPDATE_SUCCESS}" != "true" ]]
then
if [[ "${EXPLICIT_ALREADY_CURRENT}" == "true" ]]
then
echo
echo "occ reports that Nextcloud is already current,"
echo "but 'Update successful' was not found in either"
echo "the startup log or explicit occ upgrade output."
fi
fail "Could not confirm 'Update successful'"
fi
# ========================================================
# Validate Nextcloud state after DB migration
# ========================================================
log "Validate Nextcloud status after upgrade"
FINAL_STATUS="$(
docker exec \
-u www-data \
nextcloud \
php occ status
)"
echo "${FINAL_STATUS}"
echo "${FINAL_STATUS}" |
grep -Eq 'needsDbUpgrade:[[:space:]]*false' || \
fail "needsDbUpgrade is not false"
echo "${FINAL_STATUS}" |
grep -Eq 'maintenance:[[:space:]]*false' || \
fail "maintenance is not false"
# --------------------------------------------------------
# Nextcloud:
#
# 0 = normal
# 1 = maintenance
# 2 = DB upgrade required
# --------------------------------------------------------
docker exec \
-u www-data \
nextcloud \
php occ status -e
echo
echo "Nextcloud database state validated successfully."
# ========================================================
# Start cron using upgraded image
# ========================================================
log "Start Nextcloud cron"
docker compose \
up -d \
--no-deps \
cron
# ========================================================
# Apply remaining Compose changes
# ========================================================
log "Apply remaining Compose changes"
docker compose \
up -d \
--remove-orphans
# ============================================================
# NO NEXTCLOUD VERSION CHANGE
# ============================================================
else
log "No Nextcloud version change"
echo "Current version:"
echo " ${CURRENT_NC_VERSION}"
docker compose \
up -d \
--remove-orphans
fi
# ============================================================
# Final container checks
# ============================================================
log "Final container checks"
for CONTAINER in \
nextcloud \
nextcloud-cron \
nextcloud-redis
do
RUNNING="$(
docker inspect \
-f '{{.State.Running}}' \
"${CONTAINER}" 2>/dev/null ||
echo false
)"
if [[ "${RUNNING}" != "true" ]]
then
fail "${CONTAINER} is not running"
fi
echo "${CONTAINER}: running"
done
# ============================================================
# Final Nextcloud status
# ============================================================
log "Final OCC status"
FINAL_STATUS="$(
docker exec \
-u www-data \
nextcloud \
php occ status
)"
echo "${FINAL_STATUS}"
echo "${FINAL_STATUS}" |
grep -Eq 'needsDbUpgrade:[[:space:]]*false' || \
fail "Final needsDbUpgrade is not false"
echo "${FINAL_STATUS}" |
grep -Eq 'maintenance:[[:space:]]*false' || \
fail "Final maintenance is not false"
docker exec \
-u www-data \
nextcloud \
php occ status -e
# ============================================================
# Show actual running version
# ============================================================
RUNNING_NC_VERSION="$(
docker exec \
nextcloud \
php -r '
require "/var/www/html/version.php";
echo implode(".", $OC_Version);
'
)"
RUNNING_IMAGE="$(
docker inspect \
-f '{{.Config.Image}}' \
nextcloud
)"
# ============================================================
# Success
# ============================================================
log "Nextcloud deployment successful"
echo "Previous Nextcloud version:"
echo " ${CURRENT_NC_VERSION}"
echo
echo "Running Nextcloud version:"
echo " ${RUNNING_NC_VERSION}"
echo
echo "Previous Docker image:"
echo " ${OLD_IMAGE}"
echo
echo "Running Docker image:"
echo " ${RUNNING_IMAGE}"
if [[ "${VERSION_CHANGED}" == "true" ]]
then
echo
echo "Pre-upgrade backup:"
echo " ${BACKUP_DIR}"
echo
echo "PostgreSQL dump:"
echo " ${DB_BACKUP_FILE}"
echo
echo "Backup retention:"
echo " last ${BACKUP_KEEP} backups"
fi
# ============================================================
# Remove credentials from process environment
# ============================================================
unset PGPASSWORD
unset POSTGRES_PASSWORD