Files
flyer-crawler.projectium.com/.gitea/workflows/manual-db-restore.yml
Torben Sorensen e63999694a
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 1m1s
added address table, super awesome - bunch of gitea workflow options - "Processed Flyers" made better
2025-12-03 19:34:47 -08:00

96 lines
4.3 KiB
YAML

# .gitea/workflows/manual-db-restore.yml
#
# DANGER: This workflow is DESTRUCTIVE. It restores the production database from a backup file.
# It should be run manually with extreme caution.
name: Manual - Restore Production Database from Backup
on:
workflow_dispatch:
inputs:
backup_filename:
description: 'The exact filename of the backup (.sql.gz) located in /var/www/backups/'
required: true
confirmation:
description: 'DANGER: This will WIPE the production DB. Type "restore-production-db" to confirm.'
required: true
default: 'do-not-run'
jobs:
restore-database:
runs-on: projectium.com # This job runs on your self-hosted Gitea runner.
env:
# Use production database credentials for this entire job.
DB_HOST: ${{ secrets.DB_HOST }}
DB_PORT: ${{ secrets.DB_PORT }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_DATABASE: ${{ secrets.DB_DATABASE_PROD }}
BACKUP_DIR: "/var/www/backups" # Define a dedicated directory for backups
steps:
- name: Validate Secrets and Inputs
run: |
if [ -z "$DB_HOST" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ] || [ -z "$DB_DATABASE" ]; then
echo "ERROR: One or more production database secrets are not set in Gitea repository settings."
exit 1
fi
if [ "${{ gitea.event.inputs.confirmation }}" != "restore-production-db" ]; then
echo "ERROR: Confirmation phrase did not match. Aborting database restore."
exit 1
fi
if [ -z "${{ gitea.event.inputs.backup_filename }}" ]; then
echo "ERROR: Backup filename cannot be empty."
exit 1
fi
echo "✅ Confirmation accepted. Proceeding with database restore."
- name: 🚨 FINAL WARNING & PAUSE 🚨
run: |
echo "*********************************************************************"
echo "WARNING: YOU ARE ABOUT TO WIPE AND RESTORE THE PRODUCTION DATABASE."
echo "This action is IRREVERSIBLE. Press Ctrl+C in the runner terminal NOW to cancel."
echo "Restoring from file: ${{ gitea.event.inputs.backup_filename }}"
echo "Sleeping for 10 seconds..."
echo "*********************************************************************"
sleep 10
- name: Step 1 - Stop Application Server
run: |
echo "Stopping all PM2 processes to release database connections..."
pm2 stop all || echo "PM2 processes were not running."
echo "✅ Application server stopped."
- name: Step 2 - Drop and Recreate Database
run: |
echo "Dropping and recreating the production database..."
# Connect as the superuser (postgres) to drop the database.
# First, terminate all active connections to the database.
sudo -u postgres psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${DB_DATABASE}';"
# Now, drop and recreate it.
sudo -u postgres psql -c "DROP DATABASE IF EXISTS \"${DB_DATABASE}\";"
sudo -u postgres psql -c "CREATE DATABASE \"${DB_DATABASE}\" WITH OWNER = ${DB_USER};"
echo "✅ Database dropped and recreated successfully."
- name: Step 3 - Restore Database from Backup
run: |
BACKUP_FILE_PATH="${BACKUP_DIR}/${{ gitea.event.inputs.backup_filename }}"
echo "Restoring database from: $BACKUP_FILE_PATH"
if [ ! -f "$BACKUP_FILE_PATH" ]; then
echo "ERROR: Backup file not found at $BACKUP_FILE_PATH"
exit 1
fi
# Uncompress the gzipped file and pipe the SQL commands directly into psql.
# This is efficient as it doesn't require an intermediate uncompressed file.
gunzip < "$BACKUP_FILE_PATH" | PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_DATABASE"
echo "✅ Database restore completed successfully."
- name: Step 4 - Restart Application Server
run: |
echo "Restarting application server..."
cd /var/www/flyer-crawler.projectium.com
pm2 startOrReload ecosystem.config.cjs --env production && pm2 save
echo "✅ Application server restarted."