package main import ( "context" "flag" "fmt" "os" "os/signal" "syscall" "time" "veza-backend-api/internal/services" "go.uber.org/zap" ) func main() { // Parse command line flags backupDir := flag.String("backup-dir", "/backups/postgres", "Directory to store backups") retentionDays := flag.Int("retention-days", 30, "Number of days to retain backups") createBackup := flag.Bool("create", false, "Create a new backup") cleanup := flag.Bool("cleanup", false, "Cleanup old backups") list := flag.Bool("list", false, "List all backups") flag.Parse() // Initialize logger logger, err := zap.NewProduction() if err != nil { fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err) os.Exit(1) } defer logger.Sync() // Get database connection details from environment variables databaseURL := os.Getenv("DATABASE_URL") databaseName := os.Getenv("DB_NAME") if databaseName == "" { databaseName = "veza_db" // Default } databaseUser := os.Getenv("DB_USER") if databaseUser == "" { databaseUser = "veza_user" // Default } databaseHost := os.Getenv("DB_HOST") if databaseHost == "" { databaseHost = "localhost" // Default } databasePort := os.Getenv("DB_PORT") if databasePort == "" { databasePort = "5432" // Default } // If DATABASE_URL is not set, try to construct it from individual components if databaseURL == "" { // Use individual components for pg_dump } // Create backup service backupConfig := services.BackupConfig{ BackupDir: *backupDir, RetentionDays: *retentionDays, DatabaseURL: databaseURL, DatabaseName: databaseName, DatabaseUser: databaseUser, DatabaseHost: databaseHost, DatabasePort: databasePort, } backupService, err := services.NewBackupService(backupConfig, logger) if err != nil { logger.Fatal("Failed to create backup service", zap.Error(err)) } // Create context with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) defer cancel() // Handle signals for graceful shutdown sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigChan logger.Info("Received shutdown signal, cancelling backup operation") cancel() }() // Execute requested action if *createBackup { logger.Info("Creating database backup") result, err := backupService.CreateBackup(ctx) if err != nil { logger.Fatal("Backup failed", zap.Error(err)) } if result.Success { logger.Info("Backup completed successfully", zap.String("backup_path", result.BackupPath), zap.Int64("backup_size", result.BackupSize), zap.Duration("duration", result.Duration)) } else { logger.Fatal("Backup failed", zap.String("error", result.ErrorMessage)) } } else if *cleanup { logger.Info("Cleaning up old backups") if err := backupService.CleanupOldBackups(ctx); err != nil { logger.Fatal("Cleanup failed", zap.Error(err)) } logger.Info("Cleanup completed successfully") } else if *list { logger.Info("Listing backups") backups, err := backupService.ListBackups(ctx) if err != nil { logger.Fatal("Failed to list backups", zap.Error(err)) } fmt.Printf("\nFound %d backups:\n\n", len(backups)) for _, backup := range backups { sizeMB := float64(backup.Size) / (1024 * 1024) fmt.Printf(" %s\n", backup.FileName) fmt.Printf(" Path: %s\n", backup.FilePath) fmt.Printf(" Size: %.2f MB\n", sizeMB) fmt.Printf(" Created: %s\n\n", backup.CreatedAt.Format(time.RFC3339)) } } else { // Default: create backup and cleanup logger.Info("Creating backup and cleaning up old backups") result, err := backupService.CreateBackup(ctx) if err != nil { logger.Fatal("Backup failed", zap.Error(err)) } if result.Success { logger.Info("Backup completed successfully", zap.String("backup_path", result.BackupPath), zap.Int64("backup_size", result.BackupSize), zap.Duration("duration", result.Duration)) } // Cleanup old backups if err := backupService.CleanupOldBackups(ctx); err != nil { logger.Warn("Cleanup failed", zap.Error(err)) } } }