Fix: Interactive cluster restore cleanup no longer requires database connection

Issue: When enabling cluster cleanup (Option C) in interactive restore mode,
the tool tried to connect to the database to drop existing databases. This
was confusing because:
- Cluster restore itself doesn't use database connections
- It uses CLI tools (psql, pg_restore) directly
- Connection errors were misleading to users

Solution: Changed cleanup to use psql command directly (dropDatabaseCLI)
- Matches how cluster restore works (CLI tools, not connections)
- No confusing connection errors
- Cleaner, more consistent behavior
- Uses postgres maintenance DB for DROP DATABASE commands

Files changed:
- internal/tui/restore_exec.go: Added dropDatabaseCLI() helper function
- Removed dbClient.Connect() requirement for cleanup
- Cleanup now works exactly like cluster restore operations
This commit is contained in:
2025-11-12 08:31:14 +00:00
parent 6531a94726
commit 6239e57a20

View File

@@ -3,6 +3,7 @@ package tui
import ( import (
"context" "context"
"fmt" "fmt"
"os/exec"
"strings" "strings"
"time" "time"
@@ -115,19 +116,11 @@ func executeRestoreWithTUIProgress(cfg *config.Config, log logger.Logger, archiv
if restoreType == "restore-cluster" && cleanClusterFirst && len(existingDBs) > 0 { if restoreType == "restore-cluster" && cleanClusterFirst && len(existingDBs) > 0 {
log.Info("Dropping existing user databases before cluster restore", "count", len(existingDBs)) log.Info("Dropping existing user databases before cluster restore", "count", len(existingDBs))
// Connect to database for cleanup // Drop databases using command-line psql (no connection required)
if err := dbClient.Connect(ctx); err != nil { // This matches how cluster restore works - uses CLI tools, not database connections
return restoreCompleteMsg{
result: "",
err: fmt.Errorf("failed to connect for cleanup: %w", err),
elapsed: time.Since(start),
}
}
// Drop each database
droppedCount := 0 droppedCount := 0
for _, dbName := range existingDBs { for _, dbName := range existingDBs {
if err := dbClient.DropDatabase(ctx, dbName); err != nil { if err := dropDatabaseCLI(ctx, cfg, dbName); err != nil {
log.Warn("Failed to drop database", "name", dbName, "error", err) log.Warn("Failed to drop database", "name", dbName, "error", err)
// Continue with other databases // Continue with other databases
} else { } else {
@@ -318,3 +311,34 @@ func formatDuration(d time.Duration) string {
minutes := int(d.Minutes()) % 60 minutes := int(d.Minutes()) % 60
return fmt.Sprintf("%dh %dm", hours, minutes) return fmt.Sprintf("%dh %dm", hours, minutes)
} }
// dropDatabaseCLI drops a database using command-line psql
// This avoids needing an active database connection
func dropDatabaseCLI(ctx context.Context, cfg *config.Config, dbName string) error {
args := []string{
"-p", fmt.Sprintf("%d", cfg.Port),
"-U", cfg.User,
"-d", "postgres", // Connect to postgres maintenance DB
"-c", fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbName),
}
// Only add -h flag if host is not localhost (to use Unix socket for peer auth)
if cfg.Host != "localhost" && cfg.Host != "127.0.0.1" && cfg.Host != "" {
args = append([]string{"-h", cfg.Host}, args...)
}
cmd := exec.CommandContext(ctx, "psql", args...)
// Set password if provided
if cfg.Password != "" {
cmd.Env = append(cmd.Environ(), fmt.Sprintf("PGPASSWORD=%s", cfg.Password))
}
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to drop database %s: %w\nOutput: %s", dbName, err, string(output))
}
return nil
}