Files
docker-compose-selfhost/rollback_postgres_upgrade.sh

115 lines
3.7 KiB
Bash
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
COMPOSE=./docker-compose.yaml
SERVICE=postgres
DATA_DIR=./database
ROLLBACK_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "🧪 Validating docker-compose config..."
docker compose -f "$COMPOSE" config > /dev/null || {
echo "❌ docker-compose config failed. Restore aborted."
exit 1
}
# Extract current Postgres image
CURRENT_IMG=$(docker compose -f "$COMPOSE" config | grep "image:" | grep "$SERVICE" | awk '{print $2}' || true)
if [[ -z "$CURRENT_IMG" ]]; then
echo "❌ Could not detect current image for service '$SERVICE'."
exit 1
fi
CURRENT_TAG=$(basename "$CURRENT_IMG")
CURRENT_VERSION=$(echo "$CURRENT_TAG" | cut -d'-' -f1) # e.g., 17.5
# Detect appropriate backup folder
BACKUP_CANDIDATES=($(ls -td ./database_backup_* 2>/dev/null || true))
if [[ ${#BACKUP_CANDIDATES[@]} -eq 0 ]]; then
echo "❌ No backup directory found. Cannot determine previous version."
echo " Available folders:"
ls -1d ./database_backup_* || true
exit 1
elif [[ ${#BACKUP_CANDIDATES[@]} -eq 1 ]]; then
SELECTED_BACKUP="${BACKUP_CANDIDATES[0]}"
echo " Only one backup found. Using: ${SELECTED_BACKUP}"
else
SELECTED_BACKUP="${BACKUP_CANDIDATES[1]}"
echo " Multiple backups found. Using second latest: ${SELECTED_BACKUP}"
fi
# Extract version from selected backup folder
OLD_TAG=$(basename "$SELECTED_BACKUP" | sed -E 's/database_backup_(([^_]+)-alpine).*/\1/')
OLD_IMG="postgres:${OLD_TAG}"
DELETED_UPGRADE_DIR=./database_upgraded_${CURRENT_VERSION}_${ROLLBACK_TIMESTAMP}
echo "⏪ Initiating rollback from Postgres ${CURRENT_TAG} to ${OLD_IMG}..."
# Step 1: Confirm backup exists
if [ ! -d "$SELECTED_BACKUP" ]; then
echo "❌ Backup folder '${SELECTED_BACKUP}' not found. Aborting."
exit 1
fi
# Step 2: Stop services
echo "🛑 Stopping running services..."
docker compose -f "$COMPOSE" down
# Step 3: Archive current (possibly broken) database
echo "📦 Archiving current database directory as '${DELETED_UPGRADE_DIR}'..."
mv "$DATA_DIR" "$DELETED_UPGRADE_DIR"
# Step 4: Restore previous version
echo "♻️ Restoring from backup folder '${SELECTED_BACKUP}'..."
cp -a "$SELECTED_BACKUP" "$DATA_DIR"
# Step 5: Restore image tag in docker-compose.yaml
echo "🔁 Reverting docker-compose image tag to Postgres ${OLD_IMG}..."
update_image_tag() {
local svc="$1"
local file="$2"
local target_tag="$3"
echo "🔁 Reverting docker-compose image tag for service '$svc' to Postgres: ${target_tag}..."
# Use awk to scope updates within the service definition only
awk -v service="$svc" -v new_tag="$target_tag" '
BEGIN { in_service = 0 }
/^[ ]{2}[a-zA-Z0-9_-]+:/ {
in_service = ($1 == service ":") ? 1 : 0
}
in_service && /^\s*image:/ {
sub(/postgres:[^"'"'"']+/, "postgres:" new_tag)
}
{ print }
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
}
update_image_tag "$SERVICE" "$COMPOSE" "$OLD_TAG"
# Step 6: Restart Postgres
echo "🚀 Starting Postgres service with restored image..."
docker compose -f "$COMPOSE" up -d "$SERVICE"
# Step 7: Final messages
echo "✅ Rollback complete!"
echo "🗃️ PostgreSQL downgraded to '${OLD_IMG}' and data restored from '${SELECTED_BACKUP}'."
echo "📦 The faulty upgrade has been archived in '${DELETED_UPGRADE_DIR}'."
echo " - To clean: rm -rf ${DELETED_UPGRADE_DIR}"
echo " - To verify: docker compose logs -f $SERVICE"
# Step 8: Restart full application
echo "🔄 Pulling latest images..."
if ! docker compose pull; then
echo "❌ Failed to pull images. Aborting."
exit 1
fi
echo "🔄 Starting full application stack..."
if ! docker compose up -d --force-recreate; then
echo "❌ Failed to start application stack. Please check logs."
exit 1
fi
echo "✅ Deployment completed successfully."