ferrero-opentext/Python-Version/database/backup.sh
DJP e0128d98b8 Add automated PostgreSQL backup and restore system
Implements dual backup strategy with daily SQL dumps and weekly binary
backups, complete with restore capabilities and health monitoring.

Backup System Components:

1. database/backup.sh:
   - Daily mode: pg_dump SQL dumps (7-day retention)
   - Weekly mode: pg_basebackup binary backup (latest only)
   - Automatic cleanup of old backups
   - Compression (gzip) for space efficiency
   - Email notifications on failures
   - Docker-compatible execution

2. database/restore.sh:
   - Restore from SQL dump backups
   - Safety backup before restore
   - Confirmation prompts
   - Validation and verification
   - List available backups

3. database/check_backups.sh:
   - Health check monitoring
   - Verifies latest backup age (warns if > 25 hours)
   - Displays backup counts and sizes
   - Quiet mode for cron automation
   - Lists all available backups

Documentation:

- DATABASE_BACKUP_GUIDE.md: Complete backup/restore guide
  - Automated cron setup
  - Manual backup procedures
  - Restore scenarios
  - Troubleshooting
  - Disk space management

- backups/README.md: Quick reference
  - Directory structure
  - Common commands
  - Retention policy
  - Security notes

Configuration:

- Updated .gitignore to exclude backup files
- Backup locations: backups/dumps/, backups/basebackups/
- Logs: logs/backup.log, logs/restore.log
- Retention: 7 daily dumps + 1 weekly basebackup

Cron Schedule (Production):
- Daily: 2:00 AM (pg_dump)
- Weekly: Sundays 3:00 AM (pg_basebackup)
- Health Check: 8:00 AM daily

Features:
 Automated daily and weekly backups
 Dual strategy (logical + physical)
 Space-efficient (7-day retention, ~50 MB total)
 Safety backups before restore
 Email alerts on failures
 Health monitoring
 Docker-compatible
 Tested locally

Testing Performed:
- Daily backup created successfully (77K compressed)
- Backup file integrity verified (gzip test passed)
- Health check shows "Backup system healthy"
- Restore --list command working
- All scripts executable and functional

Disk Usage Estimate:
- Daily dumps: 7 × ~2 MB = ~14 MB
- Weekly backup: 1 × ~30 MB = ~30 MB
- Total: ~50 MB maximum

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 17:30:10 -05:00

228 lines
6.3 KiB
Bash
Executable file

#!/bin/bash
#
# PostgreSQL Backup Script for Ferrero Automation
# Supports both daily (pg_dump) and weekly (pg_basebackup) backups
# Compatible with Docker containers
#
# Usage:
# ./database/backup.sh --daily # Daily SQL dump backup
# ./database/backup.sh --weekly # Weekly full binary backup
#
set -e # Exit on error
# Configuration
DB_NAME="ferrero_tracking"
DB_USER="ferrero_user"
DB_PASSWORD="ferrero_pass_2025"
DB_HOST="localhost"
DB_PORT="5437"
DOCKER_CONTAINER="ferrero-tracking-db"
# Directories
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
BACKUP_BASE_DIR="$PROJECT_DIR/backups"
DUMP_DIR="$BACKUP_BASE_DIR/dumps"
BASEBACKUP_DIR="$BACKUP_BASE_DIR/basebackups"
LOG_DIR="$PROJECT_DIR/logs"
# Retention
DAILY_RETENTION_DAYS=7
WEEKLY_RETENTION_WEEKS=1
# Timestamp
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M")
DATE_ONLY=$(date +"%Y-%m-%d")
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Logging function
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_DIR/backup.log"
}
log_error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" >&2
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1" >> "$LOG_DIR/backup.log"
}
log_warning() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1" >> "$LOG_DIR/backup.log"
}
# Create directories
mkdir -p "$DUMP_DIR" "$BASEBACKUP_DIR" "$LOG_DIR"
# Daily backup (pg_dump)
backup_daily() {
log "Starting daily backup (pg_dump)..."
BACKUP_FILE="$DUMP_DIR/${DB_NAME}_${TIMESTAMP}.sql.gz"
# Check if Docker container is running
if ! docker ps | grep -q "$DOCKER_CONTAINER"; then
log_error "Docker container $DOCKER_CONTAINER is not running"
send_error_email "Daily backup failed: Docker container not running"
exit 1
fi
# Perform pg_dump via Docker
log "Running pg_dump for database: $DB_NAME"
if docker exec "$DOCKER_CONTAINER" pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_FILE"; then
BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
log "✓ Daily backup completed: $BACKUP_FILE ($BACKUP_SIZE)"
# Cleanup old backups
log "Cleaning up backups older than $DAILY_RETENTION_DAYS days..."
find "$DUMP_DIR" -name "*.sql.gz" -type f -mtime +$DAILY_RETENTION_DAYS -delete
REMAINING_BACKUPS=$(ls -1 "$DUMP_DIR"/*.sql.gz 2>/dev/null | wc -l)
log "Remaining daily backups: $REMAINING_BACKUPS"
return 0
else
log_error "pg_dump failed"
send_error_email "Daily backup failed: pg_dump error"
exit 1
fi
}
# Weekly backup (pg_basebackup)
backup_weekly() {
log "Starting weekly backup (pg_basebackup)..."
BACKUP_DIR="$BASEBACKUP_DIR/ferrero_tracking_${TIMESTAMP}"
BACKUP_TAR="$BASEBACKUP_DIR/ferrero_tracking_${TIMESTAMP}.tar.gz"
# Check if Docker container is running
if ! docker ps | grep -q "$DOCKER_CONTAINER"; then
log_error "Docker container $DOCKER_CONTAINER is not running"
send_error_email "Weekly backup failed: Docker container not running"
exit 1
fi
log "Running pg_basebackup..."
# Create temp directory for basebackup
mkdir -p "$BACKUP_DIR"
# Perform pg_basebackup via Docker exec
if docker exec "$DOCKER_CONTAINER" pg_basebackup -U "$DB_USER" -D /tmp/backup -Ft -z -P; then
# Copy from container to host
docker cp "$DOCKER_CONTAINER:/tmp/backup/." "$BACKUP_DIR/"
# Create compressed archive
tar -czf "$BACKUP_TAR" -C "$BASEBACKUP_DIR" "$(basename "$BACKUP_DIR")"
# Remove temp directory
rm -rf "$BACKUP_DIR"
docker exec "$DOCKER_CONTAINER" rm -rf /tmp/backup
BACKUP_SIZE=$(du -h "$BACKUP_TAR" | cut -f1)
log "✓ Weekly backup completed: $BACKUP_TAR ($BACKUP_SIZE)"
# Cleanup old weekly backups (keep only latest)
log "Cleaning up old weekly backups..."
ls -t "$BASEBACKUP_DIR"/*.tar.gz | tail -n +2 | xargs -r rm --
REMAINING_BACKUPS=$(ls -1 "$BASEBACKUP_DIR"/*.tar.gz 2>/dev/null | wc -l)
log "Remaining weekly backups: $REMAINING_BACKUPS"
return 0
else
log_error "pg_basebackup failed"
rm -rf "$BACKUP_DIR"
send_error_email "Weekly backup failed: pg_basebackup error"
exit 1
fi
}
# Send error email notification
send_error_email() {
local error_message="$1"
# Check if Python is available
if command -v python3 &> /dev/null; then
log "Sending error notification email..."
# Use Python to send email via existing notifier
python3 << EOF
import sys
sys.path.insert(0, '$PROJECT_DIR')
from scripts.shared.config_loader import load_config
from scripts.shared.notifier import Notifier
try:
config = load_config('$PROJECT_DIR/config/config.yaml')
notifier = Notifier(config)
notifier.send_email(
template_name='backup_failed',
recipients=config['notifications']['recipients']['errors'],
data={
'error_message': '$error_message',
'timestamp': '$(date +'%Y-%m-%d %H:%M:%S')',
'server': '$(hostname)'
}
)
print("Error email sent")
except Exception as e:
print("Failed to send email: {}".format(str(e)))
EOF
else
log_warning "Python not available - cannot send email notification"
fi
}
# Display usage
usage() {
echo "Usage: $0 [--daily|--weekly]"
echo ""
echo "Options:"
echo " --daily Perform daily pg_dump backup"
echo " --weekly Perform weekly pg_basebackup backup"
echo ""
echo "Examples:"
echo " $0 --daily"
echo " $0 --weekly"
exit 1
}
# Main execution
main() {
log "========================================="
log "Ferrero Database Backup"
log "========================================="
# Parse arguments
if [ $# -eq 0 ]; then
usage
fi
case "$1" in
--daily)
backup_daily
;;
--weekly)
backup_weekly
;;
*)
usage
;;
esac
log "========================================="
log "Backup completed successfully"
log "========================================="
}
# Run main
main "$@"