diff --git a/opt/05-backups/scripts/backup-full-enhanced.sh b/opt/05-backups/scripts/backup-full-enhanced.sh index 5dea6e3..a093bca 100755 --- a/opt/05-backups/scripts/backup-full-enhanced.sh +++ b/opt/05-backups/scripts/backup-full-enhanced.sh @@ -290,14 +290,15 @@ backup_vault() { backup_docker_configs() { log "[CONFIG] Backing up Docker Compose files..." local backup_file="$LOCAL_BACKUP_DIR/docker-configs-$(date +%Y%m%d-%H%M%S).tar.gz" - - if tar czf "$backup_file" -C /opt . -path "*docker-compose.yml" 2>/dev/null; then + + # Find all docker-compose.yml files and create archive + if find /opt -maxdepth 4 -name "docker-compose.yml" -o -name ".env" 2>/dev/null | tar czf "$backup_file" -T - 2>/dev/null; then local size=$(du -h "$backup_file" | cut -f1) success "Docker configs backed up ($size)" - + # Keep only last 30 days find "$LOCAL_BACKUP_DIR" -name "docker-configs-*.tar.gz" -mtime +30 -delete - + return 0 else error "Failed to backup Docker configs" @@ -308,19 +309,36 @@ backup_docker_configs() { backup_application_data() { log "[DATA] Backing up Application Data..." local backup_file="$LOCAL_BACKUP_DIR/app-data-$(date +%Y%m%d-%H%M%S).tar.gz" - - local data_dirs=( + + # Build array of existing directories only + local data_dirs=() + local candidate_dirs=( "/opt/03-business/mautic/sync_v2" "/opt/02-core/supabase/supabase/docker/volumes" + "/opt/02-core/presenton/app_data" ) - + + for dir in "${candidate_dirs[@]}"; do + if [[ -d "$dir" ]]; then + data_dirs+=("$dir") + log " Adding: $dir" + else + warning " Skipping (not found): $dir" + fi + done + + if [[ ${#data_dirs[@]} -eq 0 ]]; then + warning "No application data directories found to backup" + return 1 + fi + if tar czf "$backup_file" "${data_dirs[@]}" 2>/dev/null; then local size=$(du -h "$backup_file" | cut -f1) success "Application data backed up ($size)" - + # Keep only last 14 days find "$LOCAL_BACKUP_DIR" -name "app-data-*.tar.gz" -mtime +14 -delete - + return 0 else error "Failed to backup application data" @@ -330,28 +348,49 @@ backup_application_data() { backup_with_restic() { log "=== Uploading to Restic (Cloudflare R2) ===" - + if ! command -v restic &>/dev/null; then warning "Restic not installed, skipping cloud backup" return 1 fi - + # Initialize Restic repository if needed if ! restic cat config &>/dev/null; then log "Initializing Restic repository..." restic init || warning "Restic repository might already exist" fi - + + # Create default exclude file if it doesn't exist + local exclude_file="$BACKUP_BASE/.restic-exclude" + if [[ ! -f "$exclude_file" ]]; then + cat > "$exclude_file" << 'EOF' +*.tmp +*.log +lost+found/ +.DS_Store +EOF + fi + # Backup local directory to Restic - if restic backup "$BACKUP_BASE" --exclude-file="$BACKUP_BASE/.restic-exclude" 2>/dev/null; then - success "Restic backup completed" - - # Cleanup old snapshots (keep last 30) - restic forget --keep-daily 3 --keep-weekly 1 --prune 2>/dev/null || true - + local restic_output=$(restic backup "$BACKUP_BASE" --exclude-file="$exclude_file" 2>&1) + local restic_exit=$? + + # Log the output + echo "$restic_output" | tee -a "$LOG_FILE" > /dev/null + + # Check if backup was successful + if [[ $restic_exit -eq 0 ]] && echo "$restic_output" | grep -q "snapshot.*saved"; then + local snapshot_id=$(echo "$restic_output" | grep "snapshot" | grep "saved" | awk '{print $2}') + success "Restic backup completed (snapshot: $snapshot_id)" + + # Cleanup old snapshots + log "Cleaning up old snapshots..." + restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 3 --prune 2>/dev/null || true + return 0 else - error "Restic backup failed" + error "Restic backup failed (exit code: $restic_exit)" + echo "$restic_output" | tail -10 return 1 fi } @@ -399,18 +438,31 @@ main() { local db_user="aimpress_admin" [[ "$db_container" == "authentik-postgres" ]] && db_user="authentik" [[ "$db_container" == "postiz-postgres" ]] && db_user="postiz" + [[ "$db_container" == "supabase-db" ]] && db_user="supabase_admin" - backup_postgresql "$db_container" "$db_user" && ((successful++)) || ((failed++)) + if backup_postgresql "$db_container" "$db_user"; then + ((++successful)) + else + ((++failed)) + fi ;; mariadb) - backup_mariadb "$db_container" && ((successful++)) || ((failed++)) + if backup_mariadb "$db_container"; then + ((++successful)) + else + ((++failed)) + fi ;; mongodb) - backup_mongodb "$db_container" && ((successful++)) || ((failed++)) + if backup_mongodb "$db_container"; then + ((++successful)) + else + ((++failed)) + fi ;; *) warning "Unknown database type: $db_type" - ((failed++)) + ((++failed)) ;; esac done @@ -418,19 +470,19 @@ main() { log "" log "=== PHASE 2: Configuration Backups ===" - - backup_vault && ((successful++)) || ((failed++)) - backup_docker_configs && ((successful++)) || ((failed++)) - + + if backup_vault; then ((++successful)); else ((++failed)); fi + if backup_docker_configs; then ((++successful)); else ((++failed)); fi + log "" log "=== PHASE 3: Application Data ===" - - backup_application_data && ((successful++)) || ((failed++)) - + + if backup_application_data; then ((++successful)); else ((++failed)); fi + log "" log "=== PHASE 4: Cloud Backup (Restic) ===" - - backup_with_restic && ((successful++)) || ((failed++)) + + if backup_with_restic; then ((++successful)); else ((++failed)); fi # Calculate duration local end_time=$(date +%s)