194 lines
5.5 KiB
Bash
194 lines
5.5 KiB
Bash
#!/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 "$@"
|