feat: add comprehensive PostgreSQL backup and restore scripts
All checks were successful
Basil CI/CD Pipeline / Shared Package Tests (push) Successful in 1m10s
Basil CI/CD Pipeline / Code Linting (push) Successful in 1m18s
Basil CI/CD Pipeline / Web Tests (push) Successful in 1m29s
Basil CI/CD Pipeline / Security Scanning (push) Successful in 1m14s
Basil CI/CD Pipeline / API Tests (push) Successful in 1m45s
Basil CI/CD Pipeline / Trigger Deployment (push) Successful in 12s
Basil CI/CD Pipeline / Build All Packages (push) Successful in 1m31s
Basil CI/CD Pipeline / E2E Tests (push) Has been skipped
Basil CI/CD Pipeline / Build & Push Docker Images (push) Successful in 14m27s
All checks were successful
Basil CI/CD Pipeline / Shared Package Tests (push) Successful in 1m10s
Basil CI/CD Pipeline / Code Linting (push) Successful in 1m18s
Basil CI/CD Pipeline / Web Tests (push) Successful in 1m29s
Basil CI/CD Pipeline / Security Scanning (push) Successful in 1m14s
Basil CI/CD Pipeline / API Tests (push) Successful in 1m45s
Basil CI/CD Pipeline / Trigger Deployment (push) Successful in 12s
Basil CI/CD Pipeline / Build All Packages (push) Successful in 1m31s
Basil CI/CD Pipeline / E2E Tests (push) Has been skipped
Basil CI/CD Pipeline / Build & Push Docker Images (push) Successful in 14m27s
Added production-grade backup and restore scripts for PostgreSQL servers
that can backup all databases automatically with retention management.
New scripts:
- scripts/backup-all-postgres-databases.sh - Backs up all databases on a
PostgreSQL server with automatic retention, compression, verification,
and notification support
- scripts/restore-postgres-database.sh - Restores individual databases
with safety backups and verification
- scripts/README-POSTGRES-BACKUP.md - Complete documentation with examples,
best practices, and troubleshooting
Features:
- Automatic detection and backup of all user databases
- Excludes system databases (postgres, template0, template1)
- Backs up global objects (roles, tablespaces)
- Optional gzip compression (80-90% space savings)
- Automatic retention management (configurable days)
- Integrity verification (gzip -t for compressed files)
- Safety backups before restore operations
- Detailed logging with color-coded output
- Backup summary reporting
- Email/Slack notification support (optional)
- Interactive restore with confirmation prompts
- Force mode for automation
- Verbose debugging mode
- Comprehensive error handling
Backup directory structure:
/var/backups/postgresql/YYYYMMDD/
- globals_YYYYMMDD_HHMMSS.sql.gz
- database1_YYYYMMDD_HHMMSS.sql.gz
- database2_YYYYMMDD_HHMMSS.sql.gz
Usage examples:
# Backup all databases with compression
./backup-all-postgres-databases.sh -c
# Custom configuration
./backup-all-postgres-databases.sh -h db.server.com -U backup_user -d /mnt/backups -r 60 -c
# Restore database
./restore-postgres-database.sh /var/backups/postgresql/20260120/mydb_20260120_020001.sql.gz
# Force restore (skip confirmation)
./restore-postgres-database.sh backup.sql.gz -d mydb -f
Automation:
# Add to crontab for daily backups at 2 AM
0 2 * * * /path/to/backup-all-postgres-databases.sh -c >> /var/log/postgres-backup.log 2>&1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
458
scripts/README-POSTGRES-BACKUP.md
Normal file
458
scripts/README-POSTGRES-BACKUP.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# PostgreSQL Backup Scripts
|
||||
|
||||
Comprehensive backup and restore scripts for PostgreSQL databases.
|
||||
|
||||
## Scripts Overview
|
||||
|
||||
### 1. `backup-all-postgres-databases.sh`
|
||||
Backs up all databases on a PostgreSQL server (excluding system databases).
|
||||
|
||||
**Features:**
|
||||
- ✅ Backs up all user databases automatically
|
||||
- ✅ Includes global objects (roles, tablespaces)
|
||||
- ✅ Optional gzip compression
|
||||
- ✅ Automatic retention management
|
||||
- ✅ Integrity verification
|
||||
- ✅ Detailed logging with color output
|
||||
- ✅ Backup summary reporting
|
||||
- ✅ Email/Slack notification support (optional)
|
||||
|
||||
### 2. `restore-postgres-database.sh`
|
||||
Restores a single database from backup.
|
||||
|
||||
**Features:**
|
||||
- ✅ Safety backup before restore
|
||||
- ✅ Interactive confirmation
|
||||
- ✅ Automatic database name detection
|
||||
- ✅ Compressed file support
|
||||
- ✅ Integrity verification
|
||||
- ✅ Post-restore verification
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Backup All Databases
|
||||
|
||||
```bash
|
||||
# Basic usage
|
||||
./backup-all-postgres-databases.sh
|
||||
|
||||
# With compression (recommended)
|
||||
./backup-all-postgres-databases.sh -c
|
||||
|
||||
# Custom configuration
|
||||
./backup-all-postgres-databases.sh \
|
||||
-h db.example.com \
|
||||
-U postgres \
|
||||
-d /mnt/backups \
|
||||
-r 60 \
|
||||
-c
|
||||
```
|
||||
|
||||
### Restore a Database
|
||||
|
||||
```bash
|
||||
# Interactive restore (with confirmation)
|
||||
./restore-postgres-database.sh /var/backups/postgresql/20260120/mydb_20260120_020001.sql.gz
|
||||
|
||||
# Force restore (skip confirmation)
|
||||
./restore-postgres-database.sh backup.sql.gz -d mydb -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Detailed Usage
|
||||
|
||||
### Backup Script Options
|
||||
|
||||
```bash
|
||||
./backup-all-postgres-databases.sh [options]
|
||||
|
||||
Options:
|
||||
-h HOST Database host (default: localhost)
|
||||
-p PORT Database port (default: 5432)
|
||||
-U USER Database user (default: postgres)
|
||||
-d BACKUP_DIR Backup directory (default: /var/backups/postgresql)
|
||||
-r DAYS Retention days (default: 30)
|
||||
-c Enable compression (gzip)
|
||||
-v Verbose output
|
||||
-H Show help
|
||||
```
|
||||
|
||||
### Restore Script Options
|
||||
|
||||
```bash
|
||||
./restore-postgres-database.sh <backup_file> [options]
|
||||
|
||||
Options:
|
||||
-h HOST Database host (default: localhost)
|
||||
-p PORT Database port (default: 5432)
|
||||
-U USER Database user (default: postgres)
|
||||
-d DBNAME Target database name (default: from filename)
|
||||
-f Force restore (skip confirmation)
|
||||
-v Verbose output
|
||||
-H Show help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automated Backups with Cron
|
||||
|
||||
### Daily Backups (Recommended)
|
||||
|
||||
```bash
|
||||
# Edit crontab
|
||||
sudo crontab -e
|
||||
|
||||
# Add daily backup at 2 AM with compression
|
||||
0 2 * * * /path/to/backup-all-postgres-databases.sh -c >> /var/log/postgres-backup.log 2>&1
|
||||
```
|
||||
|
||||
### Alternative Schedules
|
||||
|
||||
```bash
|
||||
# Every 6 hours
|
||||
0 */6 * * * /path/to/backup-all-postgres-databases.sh -c
|
||||
|
||||
# Twice daily (2 AM and 2 PM)
|
||||
0 2,14 * * * /path/to/backup-all-postgres-databases.sh -c
|
||||
|
||||
# Weekly on Sundays at 3 AM
|
||||
0 3 * * 0 /path/to/backup-all-postgres-databases.sh -c -r 90
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Directory Structure
|
||||
|
||||
```
|
||||
/var/backups/postgresql/
|
||||
├── 20260120/ # Date-based subdirectory
|
||||
│ ├── globals_20260120_020001.sql.gz # Global objects backup
|
||||
│ ├── basil_20260120_020001.sql.gz # Database backup
|
||||
│ ├── myapp_20260120_020001.sql.gz # Database backup
|
||||
│ └── wiki_20260120_020001.sql.gz # Database backup
|
||||
├── 20260121/
|
||||
│ ├── globals_20260121_020001.sql.gz
|
||||
│ └── ...
|
||||
└── 20260122/
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Local PostgreSQL Server
|
||||
|
||||
```bash
|
||||
./backup-all-postgres-databases.sh \
|
||||
-h localhost \
|
||||
-U postgres \
|
||||
-c
|
||||
```
|
||||
|
||||
### Remote PostgreSQL Server
|
||||
|
||||
```bash
|
||||
./backup-all-postgres-databases.sh \
|
||||
-h db.example.com \
|
||||
-p 5432 \
|
||||
-U backup_user \
|
||||
-d /mnt/network/backups \
|
||||
-r 60 \
|
||||
-c \
|
||||
-v
|
||||
```
|
||||
|
||||
### High-Frequency Backups
|
||||
|
||||
```bash
|
||||
# Short retention for frequent backups
|
||||
./backup-all-postgres-databases.sh \
|
||||
-r 7 \
|
||||
-c
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication Setup
|
||||
|
||||
### Option 1: .pgpass File (Recommended)
|
||||
|
||||
Create `~/.pgpass` with connection credentials:
|
||||
|
||||
```bash
|
||||
echo "localhost:5432:*:postgres:your-password" >> ~/.pgpass
|
||||
chmod 600 ~/.pgpass
|
||||
```
|
||||
|
||||
Format: `hostname:port:database:username:password`
|
||||
|
||||
### Option 2: Environment Variables
|
||||
|
||||
```bash
|
||||
export PGPASSWORD="your-password"
|
||||
./backup-all-postgres-databases.sh
|
||||
```
|
||||
|
||||
### Option 3: Peer Authentication (Local Only)
|
||||
|
||||
Run as the postgres system user:
|
||||
|
||||
```bash
|
||||
sudo -u postgres ./backup-all-postgres-databases.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring and Notifications
|
||||
|
||||
### Email Notifications
|
||||
|
||||
Edit the scripts and uncomment the email notification section:
|
||||
|
||||
```bash
|
||||
# In backup-all-postgres-databases.sh, uncomment:
|
||||
if command -v mail &> /dev/null; then
|
||||
echo "$summary" | mail -s "PostgreSQL Backup $status - $(hostname)" admin@example.com
|
||||
fi
|
||||
```
|
||||
|
||||
### Slack Notifications
|
||||
|
||||
Set webhook URL and uncomment:
|
||||
|
||||
```bash
|
||||
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
|
||||
|
||||
# In script, uncomment:
|
||||
if [ -n "$SLACK_WEBHOOK_URL" ]; then
|
||||
curl -X POST "$SLACK_WEBHOOK_URL" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"text\":\"PostgreSQL Backup $status\n$summary\"}"
|
||||
fi
|
||||
```
|
||||
|
||||
### Log Rotation
|
||||
|
||||
Create `/etc/logrotate.d/postgres-backup`:
|
||||
|
||||
```
|
||||
/var/log/postgres-backup.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Verification
|
||||
|
||||
### Manual Verification
|
||||
|
||||
```bash
|
||||
# List backups
|
||||
ls -lh /var/backups/postgresql/$(date +%Y%m%d)/
|
||||
|
||||
# Verify compressed file integrity
|
||||
gzip -t /var/backups/postgresql/20260120/basil_20260120_020001.sql.gz
|
||||
|
||||
# Preview backup contents
|
||||
gunzip -c backup.sql.gz | head -50
|
||||
```
|
||||
|
||||
### Test Restore (Recommended Monthly)
|
||||
|
||||
```bash
|
||||
# Restore to a test database
|
||||
./restore-postgres-database.sh backup.sql.gz -d test_restore -f
|
||||
|
||||
# Verify
|
||||
psql -d test_restore -c "\dt"
|
||||
|
||||
# Cleanup
|
||||
dropdb test_restore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
### Full Server Restore
|
||||
|
||||
1. **Install PostgreSQL** on new server
|
||||
2. **Restore global objects first**:
|
||||
```bash
|
||||
gunzip -c globals_YYYYMMDD_HHMMSS.sql.gz | psql -U postgres -d postgres
|
||||
```
|
||||
3. **Restore each database**:
|
||||
```bash
|
||||
./restore-postgres-database.sh basil_20260120_020001.sql.gz
|
||||
./restore-postgres-database.sh myapp_20260120_020001.sql.gz
|
||||
```
|
||||
|
||||
### Point-in-Time Recovery
|
||||
|
||||
For PITR capabilities, enable WAL archiving in `postgresql.conf`:
|
||||
|
||||
```
|
||||
wal_level = replica
|
||||
archive_mode = on
|
||||
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
|
||||
max_wal_senders = 3
|
||||
```
|
||||
|
||||
Then use `pg_basebackup` and WAL replay for PITR.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
# Fix backup directory permissions
|
||||
sudo chown -R postgres:postgres /var/backups/postgresql
|
||||
sudo chmod 755 /var/backups/postgresql
|
||||
|
||||
# Fix script permissions
|
||||
chmod +x backup-all-postgres-databases.sh
|
||||
```
|
||||
|
||||
### Connection Failed
|
||||
|
||||
```bash
|
||||
# Test connection manually
|
||||
psql -h localhost -U postgres -c "SELECT version();"
|
||||
|
||||
# Check pg_hba.conf
|
||||
sudo cat /etc/postgresql/*/main/pg_hba.conf
|
||||
|
||||
# Ensure proper authentication line exists:
|
||||
# local all postgres peer
|
||||
# host all all 127.0.0.1/32 scram-sha-256
|
||||
```
|
||||
|
||||
### Out of Disk Space
|
||||
|
||||
```bash
|
||||
# Check disk usage
|
||||
df -h /var/backups
|
||||
|
||||
# Clean old backups manually
|
||||
find /var/backups/postgresql -type d -name "????????" -mtime +30 -exec rm -rf {} \;
|
||||
|
||||
# Reduce retention period
|
||||
./backup-all-postgres-databases.sh -r 7
|
||||
```
|
||||
|
||||
### Backup File Corrupted
|
||||
|
||||
```bash
|
||||
# Verify integrity
|
||||
gzip -t backup.sql.gz
|
||||
|
||||
# If corrupted, use previous backup
|
||||
ls -lt /var/backups/postgresql/*/basil_*.sql.gz | head
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Large Databases
|
||||
|
||||
For very large databases, consider:
|
||||
|
||||
```bash
|
||||
# Parallel dump (PostgreSQL 9.3+)
|
||||
pg_dump -Fd -j 4 -f backup_directory mydb
|
||||
|
||||
# Custom format (smaller, faster restore)
|
||||
pg_dump -Fc mydb > backup.custom
|
||||
|
||||
# Restore from custom format
|
||||
pg_restore -d mydb backup.custom
|
||||
```
|
||||
|
||||
### Network Backups
|
||||
|
||||
```bash
|
||||
# Direct SSH backup (no local storage)
|
||||
pg_dump mydb | gzip | ssh backup-server "cat > /backups/mydb.sql.gz"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always test restores** - Backups are worthless if you can't restore
|
||||
2. **Monitor backup completion** - Set up alerts for failed backups
|
||||
3. **Use compression** - Saves 80-90% of disk space
|
||||
4. **Multiple backup locations** - Local + remote/cloud storage
|
||||
5. **Verify backup integrity** - Run gzip -t on compressed backups
|
||||
6. **Document procedures** - Keep runbooks for disaster recovery
|
||||
7. **Encrypt sensitive backups** - Use gpg for encryption if needed
|
||||
8. **Regular retention review** - Adjust based on compliance requirements
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Encryption at Rest
|
||||
|
||||
```bash
|
||||
# Encrypt backup with GPG
|
||||
pg_dump mydb | gzip | gpg --encrypt --recipient admin@example.com > backup.sql.gz.gpg
|
||||
|
||||
# Decrypt for restore
|
||||
gpg --decrypt backup.sql.gz.gpg | gunzip | psql mydb
|
||||
```
|
||||
|
||||
### Secure Transfer
|
||||
|
||||
```bash
|
||||
# Use SCP with key authentication
|
||||
scp -i ~/.ssh/backup_key backup.sql.gz backup-server:/secure/backups/
|
||||
|
||||
# Or rsync over SSH
|
||||
rsync -av -e "ssh -i ~/.ssh/backup_key" \
|
||||
/var/backups/postgresql/ \
|
||||
backup-server:/secure/backups/
|
||||
```
|
||||
|
||||
### Access Control
|
||||
|
||||
```bash
|
||||
# Restrict backup directory permissions
|
||||
chmod 700 /var/backups/postgresql
|
||||
chown postgres:postgres /var/backups/postgresql
|
||||
|
||||
# Restrict script permissions
|
||||
chmod 750 backup-all-postgres-databases.sh
|
||||
chown root:postgres backup-all-postgres-databases.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [PostgreSQL Backup Documentation](https://www.postgresql.org/docs/current/backup.html)
|
||||
- [pg_dump Manual](https://www.postgresql.org/docs/current/app-pgdump.html)
|
||||
- [pg_restore Manual](https://www.postgresql.org/docs/current/app-pgrestore.html)
|
||||
- [Continuous Archiving and PITR](https://www.postgresql.org/docs/current/continuous-archiving.html)
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check script help: `./backup-all-postgres-databases.sh -H`
|
||||
- Review logs: `tail -f /var/log/postgres-backup.log`
|
||||
- Test connection: `psql -h localhost -U postgres`
|
||||
402
scripts/backup-all-postgres-databases.sh
Executable file
402
scripts/backup-all-postgres-databases.sh
Executable file
@@ -0,0 +1,402 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# PostgreSQL All Databases Backup Script
|
||||
# Backs up all databases on a PostgreSQL server using pg_dump
|
||||
#
|
||||
# Usage:
|
||||
# ./backup-all-postgres-databases.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# -h HOST Database host (default: localhost)
|
||||
# -p PORT Database port (default: 5432)
|
||||
# -U USER Database user (default: postgres)
|
||||
# -d BACKUP_DIR Backup directory (default: /var/backups/postgresql)
|
||||
# -r DAYS Retention days (default: 30)
|
||||
# -c Enable compression (gzip)
|
||||
# -v Verbose output
|
||||
#
|
||||
# Cron example (daily at 2 AM):
|
||||
# 0 2 * * * /path/to/backup-all-postgres-databases.sh -c >> /var/log/postgres-backup.log 2>&1
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Default configuration
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="5432"
|
||||
DB_USER="postgres"
|
||||
BACKUP_DIR="/var/backups/postgresql"
|
||||
RETENTION_DAYS=30
|
||||
COMPRESS=false
|
||||
VERBOSE=false
|
||||
|
||||
# Color output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Parse command line arguments
|
||||
while getopts "h:p:U:d:r:cvH" opt; do
|
||||
case $opt in
|
||||
h) DB_HOST="$OPTARG" ;;
|
||||
p) DB_PORT="$OPTARG" ;;
|
||||
U) DB_USER="$OPTARG" ;;
|
||||
d) BACKUP_DIR="$OPTARG" ;;
|
||||
r) RETENTION_DAYS="$OPTARG" ;;
|
||||
c) COMPRESS=true ;;
|
||||
v) VERBOSE=true ;;
|
||||
H)
|
||||
echo "PostgreSQL All Databases Backup Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h HOST Database host (default: localhost)"
|
||||
echo " -p PORT Database port (default: 5432)"
|
||||
echo " -U USER Database user (default: postgres)"
|
||||
echo " -d BACKUP_DIR Backup directory (default: /var/backups/postgresql)"
|
||||
echo " -r DAYS Retention days (default: 30)"
|
||||
echo " -c Enable compression (gzip)"
|
||||
echo " -v Verbose output"
|
||||
echo " -H Show this help"
|
||||
echo ""
|
||||
exit 0
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
echo -e "${BLUE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies() {
|
||||
log_debug "Checking dependencies..."
|
||||
|
||||
if ! command -v psql &> /dev/null; then
|
||||
log_error "psql not found. Please install PostgreSQL client tools."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v pg_dump &> /dev/null; then
|
||||
log_error "pg_dump not found. Please install PostgreSQL client tools."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$COMPRESS" = true ] && ! command -v gzip &> /dev/null; then
|
||||
log_error "gzip not found. Please install gzip or disable compression."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_debug "All dependencies satisfied"
|
||||
}
|
||||
|
||||
# Test database connection
|
||||
test_connection() {
|
||||
log_debug "Testing database connection..."
|
||||
|
||||
if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT version();" &> /dev/null; then
|
||||
log_error "Cannot connect to PostgreSQL server at $DB_HOST:$DB_PORT"
|
||||
log_error "Check credentials, network connectivity, and pg_hba.conf settings"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_debug "Database connection successful"
|
||||
}
|
||||
|
||||
# Create backup directory structure
|
||||
create_backup_dirs() {
|
||||
local timestamp=$(date +%Y%m%d)
|
||||
local backup_subdir="$BACKUP_DIR/$timestamp"
|
||||
|
||||
log_debug "Creating backup directory: $backup_subdir"
|
||||
|
||||
mkdir -p "$backup_subdir"
|
||||
|
||||
if [ ! -w "$backup_subdir" ]; then
|
||||
log_error "Backup directory is not writable: $backup_subdir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$backup_subdir"
|
||||
}
|
||||
|
||||
# Get list of databases to backup
|
||||
get_databases() {
|
||||
log_debug "Retrieving database list..."
|
||||
|
||||
# Get all databases except system databases
|
||||
local databases=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -t -c \
|
||||
"SELECT datname FROM pg_database
|
||||
WHERE datname NOT IN ('postgres', 'template0', 'template1')
|
||||
AND datistemplate = false
|
||||
ORDER BY datname;")
|
||||
|
||||
if [ -z "$databases" ]; then
|
||||
log_warn "No user databases found to backup"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$databases"
|
||||
}
|
||||
|
||||
# Backup a single database
|
||||
backup_database() {
|
||||
local db_name="$1"
|
||||
local backup_dir="$2"
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_file="$backup_dir/${db_name}_${timestamp}.sql"
|
||||
|
||||
log_info "Backing up database: $db_name"
|
||||
|
||||
# Add compression extension if enabled
|
||||
if [ "$COMPRESS" = true ]; then
|
||||
backup_file="${backup_file}.gz"
|
||||
fi
|
||||
|
||||
# Perform backup
|
||||
local start_time=$(date +%s)
|
||||
|
||||
if [ "$COMPRESS" = true ]; then
|
||||
if pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$db_name" \
|
||||
--no-owner --no-privileges --create --clean | gzip > "$backup_file"; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
else
|
||||
if pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$db_name" \
|
||||
--no-owner --no-privileges --create --clean > "$backup_file"; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
fi
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
if [ "$status" = "SUCCESS" ]; then
|
||||
# Verify backup file exists and has content
|
||||
if [ ! -s "$backup_file" ]; then
|
||||
log_error "Backup file is empty: $backup_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify compressed file integrity if compression is enabled
|
||||
if [ "$COMPRESS" = true ]; then
|
||||
if ! gzip -t "$backup_file" 2>/dev/null; then
|
||||
log_error "Backup file is corrupted: $backup_file"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local file_size=$(du -h "$backup_file" | cut -f1)
|
||||
log_info "✓ $db_name backup completed - Size: $file_size, Duration: ${duration}s"
|
||||
log_debug " File: $backup_file"
|
||||
return 0
|
||||
else
|
||||
log_error "✗ $db_name backup failed"
|
||||
# Remove failed backup file
|
||||
rm -f "$backup_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Backup global objects (roles, tablespaces, etc.)
|
||||
backup_globals() {
|
||||
local backup_dir="$1"
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_file="$backup_dir/globals_${timestamp}.sql"
|
||||
|
||||
log_info "Backing up global objects (roles, tablespaces)..."
|
||||
|
||||
if [ "$COMPRESS" = true ]; then
|
||||
backup_file="${backup_file}.gz"
|
||||
fi
|
||||
|
||||
if [ "$COMPRESS" = true ]; then
|
||||
if pg_dumpall -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" --globals-only | gzip > "$backup_file"; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
else
|
||||
if pg_dumpall -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" --globals-only > "$backup_file"; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$status" = "SUCCESS" ]; then
|
||||
local file_size=$(du -h "$backup_file" | cut -f1)
|
||||
log_info "✓ Global objects backup completed - Size: $file_size"
|
||||
return 0
|
||||
else
|
||||
log_error "✗ Global objects backup failed"
|
||||
rm -f "$backup_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Clean up old backups
|
||||
cleanup_old_backups() {
|
||||
log_info "Cleaning up backups older than $RETENTION_DAYS days..."
|
||||
|
||||
local deleted_count=0
|
||||
|
||||
# Find and delete old backup directories
|
||||
while IFS= read -r old_dir; do
|
||||
log_debug "Deleting old backup directory: $old_dir"
|
||||
rm -rf "$old_dir"
|
||||
((deleted_count++))
|
||||
done < <(find "$BACKUP_DIR" -maxdepth 1 -type d -name "????????" -mtime +$RETENTION_DAYS 2>/dev/null)
|
||||
|
||||
if [ $deleted_count -gt 0 ]; then
|
||||
log_info "Deleted $deleted_count old backup directories"
|
||||
else
|
||||
log_debug "No old backups to delete"
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate backup summary
|
||||
generate_summary() {
|
||||
local backup_dir="$1"
|
||||
local total_dbs="$2"
|
||||
local successful_dbs="$3"
|
||||
local failed_dbs="$4"
|
||||
local total_size=$(du -sh "$backup_dir" 2>/dev/null | cut -f1)
|
||||
|
||||
echo ""
|
||||
log_info "================================================"
|
||||
log_info "Backup Summary"
|
||||
log_info "================================================"
|
||||
log_info "Backup Directory: $backup_dir"
|
||||
log_info "Total Databases: $total_dbs"
|
||||
log_info "Successful: $successful_dbs"
|
||||
log_info "Failed: $failed_dbs"
|
||||
log_info "Total Size: $total_size"
|
||||
log_info "Retention: $RETENTION_DAYS days"
|
||||
log_info "Compression: $([ "$COMPRESS" = true ] && echo "Enabled" || echo "Disabled")"
|
||||
log_info "================================================"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Send notification (optional)
|
||||
send_notification() {
|
||||
local status="$1"
|
||||
local summary="$2"
|
||||
|
||||
# Uncomment and configure to enable email notifications
|
||||
# if command -v mail &> /dev/null; then
|
||||
# echo "$summary" | mail -s "PostgreSQL Backup $status - $(hostname)" your-email@example.com
|
||||
# fi
|
||||
|
||||
# Uncomment and configure to enable Slack notifications
|
||||
# if [ -n "$SLACK_WEBHOOK_URL" ]; then
|
||||
# curl -X POST "$SLACK_WEBHOOK_URL" \
|
||||
# -H 'Content-Type: application/json' \
|
||||
# -d "{\"text\":\"PostgreSQL Backup $status\n$summary\"}"
|
||||
# fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
|
||||
log_info "================================================"
|
||||
log_info "PostgreSQL All Databases Backup Script"
|
||||
log_info "================================================"
|
||||
log_info "Host: $DB_HOST:$DB_PORT"
|
||||
log_info "User: $DB_USER"
|
||||
log_info "Backup Directory: $BACKUP_DIR"
|
||||
log_info "Compression: $([ "$COMPRESS" = true ] && echo "Enabled" || echo "Disabled")"
|
||||
log_info "Retention: $RETENTION_DAYS days"
|
||||
log_info "================================================"
|
||||
echo ""
|
||||
|
||||
# Perform checks
|
||||
check_dependencies
|
||||
test_connection
|
||||
|
||||
# Create backup directory
|
||||
local backup_subdir=$(create_backup_dirs)
|
||||
|
||||
# Get list of databases
|
||||
local databases=$(get_databases)
|
||||
|
||||
if [ -z "$databases" ]; then
|
||||
log_warn "No databases to backup. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Backup global objects first
|
||||
backup_globals "$backup_subdir"
|
||||
|
||||
# Backup each database
|
||||
local total_dbs=0
|
||||
local successful_dbs=0
|
||||
local failed_dbs=0
|
||||
|
||||
while IFS= read -r db; do
|
||||
# Trim whitespace
|
||||
db=$(echo "$db" | xargs)
|
||||
|
||||
if [ -n "$db" ]; then
|
||||
((total_dbs++))
|
||||
|
||||
if backup_database "$db" "$backup_subdir"; then
|
||||
((successful_dbs++))
|
||||
else
|
||||
((failed_dbs++))
|
||||
fi
|
||||
fi
|
||||
done <<< "$databases"
|
||||
|
||||
# Cleanup old backups
|
||||
cleanup_old_backups
|
||||
|
||||
# Calculate total execution time
|
||||
local end_time=$(date +%s)
|
||||
local total_duration=$((end_time - start_time))
|
||||
|
||||
# Generate summary
|
||||
generate_summary "$backup_subdir" "$total_dbs" "$successful_dbs" "$failed_dbs"
|
||||
|
||||
log_info "Total execution time: ${total_duration}s"
|
||||
|
||||
# Send notification
|
||||
if [ $failed_dbs -gt 0 ]; then
|
||||
send_notification "COMPLETED WITH ERRORS" "$(generate_summary "$backup_subdir" "$total_dbs" "$successful_dbs" "$failed_dbs")"
|
||||
exit 1
|
||||
else
|
||||
send_notification "SUCCESS" "$(generate_summary "$backup_subdir" "$total_dbs" "$successful_dbs" "$failed_dbs")"
|
||||
log_info "All backups completed successfully! ✓"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
396
scripts/restore-postgres-database.sh
Executable file
396
scripts/restore-postgres-database.sh
Executable file
@@ -0,0 +1,396 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# PostgreSQL Database Restore Script
|
||||
# Restores a single database from backup created by backup-all-postgres-databases.sh
|
||||
#
|
||||
# Usage:
|
||||
# ./restore-postgres-database.sh <backup_file> [options]
|
||||
#
|
||||
# Options:
|
||||
# -h HOST Database host (default: localhost)
|
||||
# -p PORT Database port (default: 5432)
|
||||
# -U USER Database user (default: postgres)
|
||||
# -d DBNAME Target database name (default: extracted from backup filename)
|
||||
# -f Force restore (skip confirmation)
|
||||
# -v Verbose output
|
||||
#
|
||||
# Examples:
|
||||
# ./restore-postgres-database.sh /var/backups/postgresql/20260120/mydb_20260120_020001.sql.gz
|
||||
# ./restore-postgres-database.sh backup.sql -d mydb -f
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Default configuration
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="5432"
|
||||
DB_USER="postgres"
|
||||
DB_NAME=""
|
||||
FORCE=false
|
||||
VERBOSE=false
|
||||
|
||||
# Color output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
echo -e "${BLUE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Show usage
|
||||
show_usage() {
|
||||
echo "PostgreSQL Database Restore Script"
|
||||
echo ""
|
||||
echo "Usage: $0 <backup_file> [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h HOST Database host (default: localhost)"
|
||||
echo " -p PORT Database port (default: 5432)"
|
||||
echo " -U USER Database user (default: postgres)"
|
||||
echo " -d DBNAME Target database name (default: extracted from filename)"
|
||||
echo " -f Force restore (skip confirmation)"
|
||||
echo " -v Verbose output"
|
||||
echo " -H Show this help"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 /var/backups/postgresql/20260120/mydb_20260120_020001.sql.gz"
|
||||
echo " $0 backup.sql -d mydb -f"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Extract database name from backup filename
|
||||
extract_db_name() {
|
||||
local filename=$(basename "$1")
|
||||
# Remove extension(s) and timestamp
|
||||
# Format: dbname_YYYYMMDD_HHMMSS.sql[.gz]
|
||||
echo "$filename" | sed -E 's/_[0-9]{8}_[0-9]{6}\.sql(\.gz)?$//'
|
||||
}
|
||||
|
||||
# Check if file is compressed
|
||||
is_compressed() {
|
||||
[[ "$1" == *.gz ]]
|
||||
}
|
||||
|
||||
# Verify backup file
|
||||
verify_backup() {
|
||||
local backup_file="$1"
|
||||
|
||||
log_debug "Verifying backup file: $backup_file"
|
||||
|
||||
if [ ! -f "$backup_file" ]; then
|
||||
log_error "Backup file not found: $backup_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -r "$backup_file" ]; then
|
||||
log_error "Backup file is not readable: $backup_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -s "$backup_file" ]; then
|
||||
log_error "Backup file is empty: $backup_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify compressed file integrity
|
||||
if is_compressed "$backup_file"; then
|
||||
log_debug "Verifying gzip integrity..."
|
||||
if ! gzip -t "$backup_file" 2>/dev/null; then
|
||||
log_error "Backup file is corrupted (gzip test failed)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_debug "Backup file verification passed"
|
||||
}
|
||||
|
||||
# Test database connection
|
||||
test_connection() {
|
||||
log_debug "Testing database connection..."
|
||||
|
||||
if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -c "SELECT version();" &> /dev/null; then
|
||||
log_error "Cannot connect to PostgreSQL server at $DB_HOST:$DB_PORT"
|
||||
log_error "Check credentials, network connectivity, and pg_hba.conf settings"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_debug "Database connection successful"
|
||||
}
|
||||
|
||||
# Check if database exists
|
||||
database_exists() {
|
||||
local db_name="$1"
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -t -c \
|
||||
"SELECT 1 FROM pg_database WHERE datname='$db_name';" | grep -q 1
|
||||
}
|
||||
|
||||
# Create safety backup
|
||||
create_safety_backup() {
|
||||
local db_name="$1"
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local safety_file="/tmp/${db_name}_pre-restore_${timestamp}.sql.gz"
|
||||
|
||||
log_info "Creating safety backup before restore..."
|
||||
|
||||
if pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$db_name" | gzip > "$safety_file"; then
|
||||
log_info "Safety backup created: $safety_file"
|
||||
echo "$safety_file"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create safety backup"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Drop and recreate database
|
||||
recreate_database() {
|
||||
local db_name="$1"
|
||||
|
||||
log_info "Dropping and recreating database: $db_name"
|
||||
|
||||
# Terminate existing connections
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres <<EOF
|
||||
SELECT pg_terminate_backend(pid)
|
||||
FROM pg_stat_activity
|
||||
WHERE datname = '$db_name' AND pid <> pg_backend_pid();
|
||||
EOF
|
||||
|
||||
# Drop and recreate
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres <<EOF
|
||||
DROP DATABASE IF EXISTS $db_name;
|
||||
CREATE DATABASE $db_name;
|
||||
EOF
|
||||
|
||||
log_debug "Database recreated successfully"
|
||||
}
|
||||
|
||||
# Restore database
|
||||
restore_database() {
|
||||
local backup_file="$1"
|
||||
local db_name="$2"
|
||||
|
||||
log_info "Restoring database from: $backup_file"
|
||||
|
||||
local start_time=$(date +%s)
|
||||
|
||||
# Restore based on compression
|
||||
if is_compressed "$backup_file"; then
|
||||
if gunzip -c "$backup_file" | psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -v ON_ERROR_STOP=1; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
else
|
||||
if psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres -f "$backup_file" -v ON_ERROR_STOP=1; then
|
||||
local status="SUCCESS"
|
||||
else
|
||||
local status="FAILED"
|
||||
fi
|
||||
fi
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
if [ "$status" = "SUCCESS" ]; then
|
||||
log_info "✓ Database restore completed in ${duration}s"
|
||||
return 0
|
||||
else
|
||||
log_error "✗ Database restore failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Verify restore
|
||||
verify_restore() {
|
||||
local db_name="$1"
|
||||
|
||||
log_info "Verifying restored database..."
|
||||
|
||||
# Check if database exists
|
||||
if ! database_exists "$db_name"; then
|
||||
log_error "Database not found after restore: $db_name"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get table count
|
||||
local table_count=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$db_name" -t -c \
|
||||
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';")
|
||||
table_count=$(echo "$table_count" | xargs)
|
||||
|
||||
# Get row count estimate
|
||||
local row_count=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$db_name" -t -c \
|
||||
"SELECT SUM(n_live_tup) FROM pg_stat_user_tables;")
|
||||
row_count=$(echo "$row_count" | xargs)
|
||||
row_count=${row_count:-0}
|
||||
|
||||
log_info "Database: $db_name"
|
||||
log_info "Tables: $table_count"
|
||||
log_info "Approximate rows: $row_count"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
BACKUP_FILE=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h)
|
||||
DB_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p)
|
||||
DB_PORT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-U)
|
||||
DB_USER="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d)
|
||||
DB_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
-f)
|
||||
FORCE=true
|
||||
shift
|
||||
;;
|
||||
-v)
|
||||
VERBOSE=true
|
||||
shift
|
||||
;;
|
||||
-H)
|
||||
show_usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
BACKUP_FILE="$1"
|
||||
else
|
||||
log_error "Multiple backup files specified"
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Check if backup file was provided
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
log_error "No backup file specified"
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify backup file
|
||||
verify_backup "$BACKUP_FILE"
|
||||
|
||||
# Extract database name if not provided
|
||||
if [ -z "$DB_NAME" ]; then
|
||||
DB_NAME=$(extract_db_name "$BACKUP_FILE")
|
||||
log_debug "Extracted database name: $DB_NAME"
|
||||
fi
|
||||
|
||||
log_info "================================================"
|
||||
log_info "PostgreSQL Database Restore"
|
||||
log_info "================================================"
|
||||
log_info "Backup File: $BACKUP_FILE"
|
||||
log_info "Target Database: $DB_NAME"
|
||||
log_info "Host: $DB_HOST:$DB_PORT"
|
||||
log_info "User: $DB_USER"
|
||||
log_info "================================================"
|
||||
echo ""
|
||||
|
||||
# Test connection
|
||||
test_connection
|
||||
|
||||
# Check if database exists
|
||||
local db_exists=false
|
||||
if database_exists "$DB_NAME"; then
|
||||
db_exists=true
|
||||
log_warn "Database '$DB_NAME' already exists and will be DROPPED"
|
||||
fi
|
||||
|
||||
# Confirmation prompt (unless force flag is set)
|
||||
if [ "$FORCE" != true ]; then
|
||||
echo ""
|
||||
echo -e "${RED}WARNING: This will destroy all current data in database: $DB_NAME${NC}"
|
||||
echo ""
|
||||
read -p "Are you sure you want to continue? (type 'yes' to confirm): " CONFIRM
|
||||
|
||||
if [ "$CONFIRM" != "yes" ]; then
|
||||
log_info "Restore cancelled by user"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create safety backup if database exists
|
||||
local safety_file=""
|
||||
if [ "$db_exists" = true ]; then
|
||||
safety_file=$(create_safety_backup "$DB_NAME")
|
||||
fi
|
||||
|
||||
# Recreate database
|
||||
recreate_database "$DB_NAME"
|
||||
|
||||
# Restore from backup
|
||||
if restore_database "$BACKUP_FILE" "$DB_NAME"; then
|
||||
verify_restore "$DB_NAME"
|
||||
|
||||
echo ""
|
||||
log_info "================================================"
|
||||
log_info "Restore completed successfully! ✓"
|
||||
log_info "================================================"
|
||||
|
||||
if [ -n "$safety_file" ]; then
|
||||
echo ""
|
||||
log_info "A safety backup was created before restore:"
|
||||
log_info " $safety_file"
|
||||
echo ""
|
||||
log_info "To rollback to the previous state, run:"
|
||||
log_info " $0 $safety_file -d $DB_NAME -f"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
exit 0
|
||||
else
|
||||
log_error "Restore failed!"
|
||||
|
||||
if [ -n "$safety_file" ]; then
|
||||
echo ""
|
||||
log_warn "You can restore the previous state using:"
|
||||
log_warn " $0 $safety_file -d $DB_NAME -f"
|
||||
fi
|
||||
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
Reference in New Issue
Block a user