← back to Watches

scripts/backup-automation.sh

345 lines

#!/bin/bash

################################################################################
# OMEGA WATCHES - AUTOMATED BACKUP SYSTEM
# Supports daily, weekly, monthly backups with retention policies
################################################################################

set -euo pipefail

# Configuration
APP_NAME="omega-watches"
APP_DIR="/root/Projects/watches"
BACKUP_ROOT="$APP_DIR/backups"
DAILY_DIR="$BACKUP_ROOT/daily"
WEEKLY_DIR="$BACKUP_ROOT/weekly"
MONTHLY_DIR="$BACKUP_ROOT/monthly"
LOG_FILE="$APP_DIR/logs/backup-$(date +%Y%m%d).log"

# Retention policies (in days)
DAILY_RETENTION=7
WEEKLY_RETENTION=30
MONTHLY_RETENTION=365

# Remote backup (optional - configure as needed)
REMOTE_BACKUP_ENABLED=false
REMOTE_HOST=""
REMOTE_DIR=""
REMOTE_USER=""

# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

# Logging
mkdir -p "$(dirname "$LOG_FILE")"

log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE"
}

log_warning() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE"
}

# Create backup directories
setup_directories() {
    mkdir -p "$DAILY_DIR" "$WEEKLY_DIR" "$MONTHLY_DIR"
    mkdir -p "$APP_DIR/logs"
}

# Perform backup
perform_backup() {
    local backup_type=$1
    local backup_dir=$2
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_file="$backup_dir/backup-${backup_type}-${timestamp}.tar.gz"

    log "Creating $backup_type backup..."

    cd "$APP_DIR"

    # Create backup archive
    tar -czf "$backup_file" \
        --exclude='node_modules' \
        --exclude='backups' \
        --exclude='logs/*.log' \
        --exclude='.git' \
        --exclude='deploy-green' \
        --exclude='*.tmp' \
        data/ \
        dist/ \
        server.js \
        package.json \
        public/ \
        ecosystem.config.cjs \
        monitoring/ \
        nginx/ \
        scripts/ \
        2>/dev/null || true

    if [ -f "$backup_file" ]; then
        local size=$(du -h "$backup_file" | cut -f1)
        log "Backup created: $(basename "$backup_file") (Size: $size) ✓"

        # Calculate checksum
        local checksum=$(sha256sum "$backup_file" | cut -d' ' -f1)
        echo "$checksum  $(basename "$backup_file")" > "$backup_file.sha256"

        echo "$backup_file"
        return 0
    else
        log_error "Backup creation failed!"
        return 1
    fi
}

# Daily backup
daily_backup() {
    log "=== DAILY BACKUP STARTED ==="

    if perform_backup "daily" "$DAILY_DIR"; then
        cleanup_old_backups "$DAILY_DIR" $DAILY_RETENTION
        log "Daily backup completed ✓"
    else
        log_error "Daily backup failed!"
        return 1
    fi
}

# Weekly backup
weekly_backup() {
    log "=== WEEKLY BACKUP STARTED ==="

    if perform_backup "weekly" "$WEEKLY_DIR"; then
        cleanup_old_backups "$WEEKLY_DIR" $WEEKLY_RETENTION
        log "Weekly backup completed ✓"
    else
        log_error "Weekly backup failed!"
        return 1
    fi
}

# Monthly backup
monthly_backup() {
    log "=== MONTHLY BACKUP STARTED ==="

    if perform_backup "monthly" "$MONTHLY_DIR"; then
        cleanup_old_backups "$MONTHLY_DIR" $MONTHLY_RETENTION
        log "Monthly backup completed ✓"
    else
        log_error "Monthly backup failed!"
        return 1
    fi
}

# Cleanup old backups
cleanup_old_backups() {
    local dir=$1
    local retention_days=$2

    log "Cleaning up backups older than $retention_days days in $(basename "$dir")..."

    find "$dir" -name "backup-*.tar.gz" -mtime +$retention_days -delete 2>/dev/null || true
    find "$dir" -name "backup-*.tar.gz.sha256" -mtime +$retention_days -delete 2>/dev/null || true

    local count=$(ls -1 "$dir"/backup-*.tar.gz 2>/dev/null | wc -l)
    log "Remaining backups in $(basename "$dir"): $count"
}

# Upload to remote server (if enabled)
upload_to_remote() {
    local backup_file=$1

    if [ "$REMOTE_BACKUP_ENABLED" != "true" ]; then
        return 0
    fi

    if [ -z "$REMOTE_HOST" ] || [ -z "$REMOTE_DIR" ] || [ -z "$REMOTE_USER" ]; then
        log_warning "Remote backup not configured properly. Skipping upload."
        return 0
    fi

    log "Uploading backup to remote server..."

    scp "$backup_file" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" 2>&1 | tee -a "$LOG_FILE"
    scp "$backup_file.sha256" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" 2>&1 | tee -a "$LOG_FILE"

    if [ $? -eq 0 ]; then
        log "Remote upload completed ✓"
    else
        log_error "Remote upload failed!"
    fi
}

# List all backups
list_backups() {
    echo ""
    echo "=== BACKUP INVENTORY ==="
    echo ""

    echo "DAILY BACKUPS:"
    ls -lh "$DAILY_DIR"/backup-*.tar.gz 2>/dev/null || echo "  No daily backups found"
    echo ""

    echo "WEEKLY BACKUPS:"
    ls -lh "$WEEKLY_DIR"/backup-*.tar.gz 2>/dev/null || echo "  No weekly backups found"
    echo ""

    echo "MONTHLY BACKUPS:"
    ls -lh "$MONTHLY_DIR"/backup-*.tar.gz 2>/dev/null || echo "  No monthly backups found"
    echo ""
}

# Show backup statistics
show_stats() {
    echo ""
    echo "=== BACKUP STATISTICS ==="
    echo ""

    local daily_count=$(ls -1 "$DAILY_DIR"/backup-*.tar.gz 2>/dev/null | wc -l)
    local weekly_count=$(ls -1 "$WEEKLY_DIR"/backup-*.tar.gz 2>/dev/null | wc -l)
    local monthly_count=$(ls -1 "$MONTHLY_DIR"/backup-*.tar.gz 2>/dev/null | wc -l)

    local daily_size=$(du -sh "$DAILY_DIR" 2>/dev/null | cut -f1)
    local weekly_size=$(du -sh "$WEEKLY_DIR" 2>/dev/null | cut -f1)
    local monthly_size=$(du -sh "$MONTHLY_DIR" 2>/dev/null | cut -f1)
    local total_size=$(du -sh "$BACKUP_ROOT" 2>/dev/null | cut -f1)

    echo "Daily Backups:   $daily_count files ($daily_size)"
    echo "Weekly Backups:  $weekly_count files ($weekly_size)"
    echo "Monthly Backups: $monthly_count files ($monthly_size)"
    echo ""
    echo "Total Backup Size: $total_size"
    echo ""

    # Latest backups
    echo "Latest Backups:"
    echo "  Daily:   $(ls -t "$DAILY_DIR"/backup-*.tar.gz 2>/dev/null | head -1 | xargs basename 2>/dev/null || echo 'None')"
    echo "  Weekly:  $(ls -t "$WEEKLY_DIR"/backup-*.tar.gz 2>/dev/null | head -1 | xargs basename 2>/dev/null || echo 'None')"
    echo "  Monthly: $(ls -t "$MONTHLY_DIR"/backup-*.tar.gz 2>/dev/null | head -1 | xargs basename 2>/dev/null || echo 'None')"
    echo ""
}

# Restore from backup
restore_backup() {
    local backup_file=$1

    if [ -z "$backup_file" ]; then
        log_error "No backup file specified!"
        echo "Usage: $0 restore <backup-file>"
        return 1
    fi

    if [ ! -f "$backup_file" ]; then
        log_error "Backup file not found: $backup_file"
        return 1
    fi

    # Verify checksum if available
    if [ -f "$backup_file.sha256" ]; then
        log "Verifying backup integrity..."
        if sha256sum -c "$backup_file.sha256" 2>&1 | grep -q OK; then
            log "Backup integrity verified ✓"
        else
            log_error "Backup integrity check failed!"
            return 1
        fi
    fi

    log "Restoring from: $backup_file"

    # Create restore point
    local restore_point="$BACKUP_ROOT/pre-restore-$(date +%Y%m%d_%H%M%S).tar.gz"
    log "Creating restore point: $restore_point"
    perform_backup "pre-restore" "$BACKUP_ROOT" > /dev/null

    # Stop application
    log "Stopping application..."
    pm2 stop $APP_NAME 2>/dev/null || true

    # Extract backup
    log "Extracting backup..."
    cd "$APP_DIR"
    tar -xzf "$backup_file"

    # Restart application
    log "Restarting application..."
    pm2 restart $APP_NAME 2>/dev/null || pm2 start ecosystem.config.cjs --name $APP_NAME

    log "Restore completed ✓"
    log "Application URL: http://45.61.58.125:7500"
}

# Verify backup integrity
verify_backups() {
    log "Verifying backup integrity..."

    local failed=0

    for backup_dir in "$DAILY_DIR" "$WEEKLY_DIR" "$MONTHLY_DIR"; do
        for backup in "$backup_dir"/backup-*.tar.gz; do
            if [ -f "$backup" ]; then
                if [ -f "$backup.sha256" ]; then
                    if sha256sum -c "$backup.sha256" 2>&1 | grep -q OK; then
                        log "✓ $(basename "$backup")"
                    else
                        log_error "✗ $(basename "$backup") - Checksum mismatch!"
                        ((failed++))
                    fi
                else
                    log_warning "⚠ $(basename "$backup") - No checksum file"
                fi
            fi
        done
    done

    if [ $failed -eq 0 ]; then
        log "All backups verified successfully ✓"
    else
        log_error "$failed backup(s) failed verification!"
    fi
}

# Main function
main() {
    setup_directories

    case "${1:-daily}" in
        daily)
            daily_backup
            ;;
        weekly)
            weekly_backup
            ;;
        monthly)
            monthly_backup
            ;;
        list)
            list_backups
            ;;
        stats)
            show_stats
            ;;
        restore)
            restore_backup "${2:-}"
            ;;
        verify)
            verify_backups
            ;;
        *)
            echo "Usage: $0 {daily|weekly|monthly|list|stats|restore <file>|verify}"
            exit 1
            ;;
    esac
}

# Run main function
main "$@"