115 lines
3.7 KiB
Bash
115 lines
3.7 KiB
Bash
#!/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." |