Files
igny8/scripts/ops/backup-db.sh
IGNY8 VPS (Salman) 4a200822bb Dev ops prep
2026-01-21 17:53:42 +00:00

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 "$@"