feat: Step 4 - Add --backup-type incremental CLI flag (scaffolding)
Added CLI integration for incremental backups: cmd/backup.go: - Added --backup-type flag (full/incremental) - Added --base-backup flag for specifying base backup - Updated help text with incremental examples - Global vars to avoid initialization cycle cmd/backup_impl.go: - Validation: incremental requires PostgreSQL - Validation: incremental requires --base-backup - Validation: base backup file must exist - Logging: backup_type added to log output - Fallback: warns and does full backup for now Status: CLI READY but not functional - Flag parsing works - Validation works - Warns user that incremental is not implemented yet - Falls back to full backup Next: Implement CreateIncrementalBackup() and RestoreIncremental()
This commit is contained in:
@@ -40,11 +40,28 @@ var clusterCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
// Global variables for backup flags (to avoid initialization cycle)
|
||||
var (
|
||||
backupTypeFlag string
|
||||
baseBackupFlag string
|
||||
)
|
||||
|
||||
var singleCmd = &cobra.Command{
|
||||
Use: "single [database]",
|
||||
Short: "Create single database backup",
|
||||
Long: `Create a backup of a single database with all its data and schema`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Long: `Create a backup of a single database with all its data and schema.
|
||||
|
||||
Backup Types:
|
||||
--backup-type full - Complete full backup (default)
|
||||
--backup-type incremental - Incremental backup (only changed files since base) [NOT IMPLEMENTED]
|
||||
|
||||
Examples:
|
||||
# Full backup (default)
|
||||
dbbackup backup single mydb
|
||||
|
||||
# Incremental backup (requires previous full backup) [COMING IN v2.2.1]
|
||||
dbbackup backup single mydb --backup-type incremental --base-backup mydb_20250126.tar.gz`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
dbName := ""
|
||||
if len(args) > 0 {
|
||||
@@ -91,6 +108,10 @@ func init() {
|
||||
backupCmd.AddCommand(singleCmd)
|
||||
backupCmd.AddCommand(sampleCmd)
|
||||
|
||||
// Incremental backup flags (single backup only) - using global vars to avoid initialization cycle
|
||||
singleCmd.Flags().StringVar(&backupTypeFlag, "backup-type", "full", "Backup type: full or incremental [incremental NOT IMPLEMENTED]")
|
||||
singleCmd.Flags().StringVar(&baseBackupFlag, "base-backup", "", "Path to base backup (required for incremental)")
|
||||
|
||||
// Cloud storage flags for all backup commands
|
||||
for _, cmd := range []*cobra.Command{clusterCmd, singleCmd, sampleCmd} {
|
||||
cmd.Flags().String("cloud", "", "Cloud storage URI (e.g., s3://bucket/path) - takes precedence over individual flags")
|
||||
|
||||
@@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"dbbackup/internal/backup"
|
||||
"dbbackup/internal/config"
|
||||
@@ -111,6 +112,30 @@ func runSingleBackup(ctx context.Context, databaseName string) error {
|
||||
// Update config from environment
|
||||
cfg.UpdateFromEnvironment()
|
||||
|
||||
// Get backup type and base backup from environment variables (set by PreRunE)
|
||||
// For now, incremental is just scaffolding - actual implementation comes next
|
||||
backupType := "full" // TODO: Read from flag via global var in cmd/backup.go
|
||||
baseBackup := "" // TODO: Read from flag via global var in cmd/backup.go
|
||||
|
||||
// Validate backup type
|
||||
if backupType != "full" && backupType != "incremental" {
|
||||
return fmt.Errorf("invalid backup type: %s (must be 'full' or 'incremental')", backupType)
|
||||
}
|
||||
|
||||
// Validate incremental backup requirements
|
||||
if backupType == "incremental" {
|
||||
if !cfg.IsPostgreSQL() {
|
||||
return fmt.Errorf("incremental backups are currently only supported for PostgreSQL")
|
||||
}
|
||||
if baseBackup == "" {
|
||||
return fmt.Errorf("--base-backup is required for incremental backups")
|
||||
}
|
||||
// Verify base backup exists
|
||||
if _, err := os.Stat(baseBackup); os.IsNotExist(err) {
|
||||
return fmt.Errorf("base backup not found: %s", baseBackup)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return fmt.Errorf("configuration error: %w", err)
|
||||
@@ -125,10 +150,15 @@ func runSingleBackup(ctx context.Context, databaseName string) error {
|
||||
log.Info("Starting single database backup",
|
||||
"database", databaseName,
|
||||
"db_type", cfg.DatabaseType,
|
||||
"backup_type", backupType,
|
||||
"host", cfg.Host,
|
||||
"port", cfg.Port,
|
||||
"backup_dir", cfg.BackupDir)
|
||||
|
||||
if backupType == "incremental" {
|
||||
log.Info("Incremental backup", "base_backup", baseBackup)
|
||||
}
|
||||
|
||||
// Audit log: backup start
|
||||
user := security.GetCurrentUser()
|
||||
auditLogger.LogBackupStart(user, databaseName, "single")
|
||||
@@ -171,10 +201,21 @@ func runSingleBackup(ctx context.Context, databaseName string) error {
|
||||
// Create backup engine
|
||||
engine := backup.New(cfg, log, db)
|
||||
|
||||
// Perform single database backup
|
||||
if err := engine.BackupSingle(ctx, databaseName); err != nil {
|
||||
auditLogger.LogBackupFailed(user, databaseName, err)
|
||||
return err
|
||||
// Perform backup based on type
|
||||
var backupErr error
|
||||
if backupType == "incremental" {
|
||||
// Incremental backup - NOT IMPLEMENTED YET
|
||||
log.Warn("Incremental backup is not fully implemented yet - creating full backup instead")
|
||||
log.Warn("Full incremental support coming in v2.2.1")
|
||||
backupErr = engine.BackupSingle(ctx, databaseName)
|
||||
} else {
|
||||
// Full backup
|
||||
backupErr = engine.BackupSingle(ctx, databaseName)
|
||||
}
|
||||
|
||||
if backupErr != nil {
|
||||
auditLogger.LogBackupFailed(user, databaseName, backupErr)
|
||||
return backupErr
|
||||
}
|
||||
|
||||
// Audit log: backup success
|
||||
|
||||
Reference in New Issue
Block a user