#!/bin/bash # ============================================================================= # IGNY8 Database Backup Script # ============================================================================= # Usage: ./backup-db.sh [daily|weekly|monthly|pre-deploy] # Creates compressed database backup with automatic retention # ============================================================================= set -e # Configuration BACKUP_TYPE="${1:-daily}" TIMESTAMP=$(date +%Y%m%d_%H%M%S) DATE_FOLDER=$(date +%Y%m%d) # Directories BACKUP_ROOT="/data/backups" DAILY_DIR="${BACKUP_ROOT}/daily" WEEKLY_DIR="${BACKUP_ROOT}/weekly" MONTHLY_DIR="${BACKUP_ROOT}/monthly" PREDEPLOY_DIR="${BACKUP_ROOT}/pre-deploy" # Database settings (from docker environment) DB_CONTAINER="postgres" DB_NAME="igny8_db" DB_USER="igny8" # Retention settings DAILY_RETENTION_DAYS=7 WEEKLY_RETENTION_WEEKS=4 MONTHLY_RETENTION_MONTHS=12 PREDEPLOY_RETENTION_COUNT=5 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log() { echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } log_success() { log "${GREEN}✅ $1${NC}" } log_warn() { log "${YELLOW}⚠️ $1${NC}" } log_error() { log "${RED}❌ $1${NC}" } # Create directories if they don't exist create_dirs() { mkdir -p "${DAILY_DIR}" mkdir -p "${WEEKLY_DIR}" mkdir -p "${MONTHLY_DIR}" mkdir -p "${PREDEPLOY_DIR}" } # Determine backup destination based on type get_backup_path() { case $BACKUP_TYPE in daily) echo "${DAILY_DIR}/${DATE_FOLDER}" ;; weekly) echo "${WEEKLY_DIR}/week_$(date +%Y_%W)" ;; monthly) echo "${MONTHLY_DIR}/$(date +%Y_%m)" ;; pre-deploy) echo "${PREDEPLOY_DIR}/${TIMESTAMP}" ;; *) log_error "Invalid backup type: $BACKUP_TYPE" exit 1 ;; esac } # Perform database backup backup_database() { local backup_dir="$1" local backup_file="${backup_dir}/db_${DB_NAME}_${TIMESTAMP}.sql.gz" mkdir -p "${backup_dir}" log "Starting database backup: ${DB_NAME}" log "Destination: ${backup_file}" # Check if postgres container is running if ! docker ps --format '{{.Names}}' | grep -q "^${DB_CONTAINER}$"; then log_error "PostgreSQL container '${DB_CONTAINER}' is not running" exit 1 fi # Perform backup with compression if docker exec "${DB_CONTAINER}" pg_dump -U "${DB_USER}" "${DB_NAME}" | gzip > "${backup_file}"; then local size=$(du -h "${backup_file}" | cut -f1) log_success "Database backup complete: ${backup_file} (${size})" # Create latest symlink ln -sf "${backup_file}" "${BACKUP_ROOT}/latest_db.sql.gz" return 0 else log_error "Database backup failed" rm -f "${backup_file}" return 1 fi } # Clean up old backups based on retention policy cleanup_old_backups() { log "Cleaning up old backups..." # Daily backups - keep last N days if [[ -d "${DAILY_DIR}" ]]; then find "${DAILY_DIR}" -type d -mtime +${DAILY_RETENTION_DAYS} -exec rm -rf {} \; 2>/dev/null || true local daily_count=$(find "${DAILY_DIR}" -type f -name "*.sql.gz" | wc -l) log "Daily backups: ${daily_count} files" fi # Weekly backups - keep last N weeks if [[ -d "${WEEKLY_DIR}" ]]; then find "${WEEKLY_DIR}" -type d -mtime +$((WEEKLY_RETENTION_WEEKS * 7)) -exec rm -rf {} \; 2>/dev/null || true local weekly_count=$(find "${WEEKLY_DIR}" -type f -name "*.sql.gz" | wc -l) log "Weekly backups: ${weekly_count} files" fi # Monthly backups - keep last N months if [[ -d "${MONTHLY_DIR}" ]]; then find "${MONTHLY_DIR}" -type d -mtime +$((MONTHLY_RETENTION_MONTHS * 30)) -exec rm -rf {} \; 2>/dev/null || true local monthly_count=$(find "${MONTHLY_DIR}" -type f -name "*.sql.gz" | wc -l) log "Monthly backups: ${monthly_count} files" fi # Pre-deploy backups - keep last N if [[ -d "${PREDEPLOY_DIR}" ]]; then local predeploy_dirs=$(ls -dt "${PREDEPLOY_DIR}"/*/ 2>/dev/null | tail -n +$((PREDEPLOY_RETENTION_COUNT + 1))) if [[ -n "$predeploy_dirs" ]]; then echo "$predeploy_dirs" | xargs rm -rf 2>/dev/null || true fi local predeploy_count=$(find "${PREDEPLOY_DIR}" -maxdepth 1 -type d | wc -l) log "Pre-deploy backups: $((predeploy_count - 1)) snapshots" fi log_success "Cleanup complete" } # Display backup summary show_summary() { echo "" echo "==========================================" echo "BACKUP SUMMARY" echo "==========================================" echo "Type: ${BACKUP_TYPE}" echo "Database: ${DB_NAME}" echo "Timestamp: ${TIMESTAMP}" echo "" echo "Disk Usage:" du -sh "${BACKUP_ROOT}"/* 2>/dev/null || echo "No backups yet" echo "" echo "Latest backup: $(readlink -f ${BACKUP_ROOT}/latest_db.sql.gz 2>/dev/null || echo 'None')" echo "==========================================" } # Main execution main() { echo "==========================================" echo "IGNY8 Database Backup" echo "==========================================" echo "" create_dirs local backup_path=$(get_backup_path) if backup_database "${backup_path}"; then cleanup_old_backups show_summary exit 0 else exit 1 fi } main "$@"