Add Option C: Smart cluster cleanup before restore (TUI)

- Auto-detects existing user databases before cluster restore
- Shows count and list (first 5) in preview screen
- Toggle option 'c' to enable cluster cleanup
- Drops all user databases before restore when enabled
- Works for PostgreSQL, MySQL, MariaDB
- Safety warning with database count
- Implements practical disaster recovery workflow
This commit is contained in:
2025-11-11 21:38:40 +00:00
parent b926bb7806
commit 661fd7e671
3 changed files with 238 additions and 36 deletions

View File

@@ -337,3 +337,85 @@ func (s *Safety) checkMySQLDatabaseExists(ctx context.Context, dbName string) (b
return strings.Contains(string(output), dbName), nil
}
// ListUserDatabases returns list of user databases (excludes templates and system DBs)
func (s *Safety) ListUserDatabases(ctx context.Context) ([]string, error) {
if s.cfg.DatabaseType == "postgres" {
return s.listPostgresUserDatabases(ctx)
} else if s.cfg.DatabaseType == "mysql" || s.cfg.DatabaseType == "mariadb" {
return s.listMySQLUserDatabases(ctx)
}
return nil, fmt.Errorf("unsupported database type: %s", s.cfg.DatabaseType)
}
// listPostgresUserDatabases lists PostgreSQL user databases
func (s *Safety) listPostgresUserDatabases(ctx context.Context) ([]string, error) {
// Query to get non-template databases excluding 'postgres' system DB
query := "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres' ORDER BY datname"
cmd := exec.CommandContext(ctx,
"psql",
"-h", s.cfg.Host,
"-p", fmt.Sprintf("%d", s.cfg.Port),
"-U", s.cfg.User,
"-d", "postgres",
"-tA", // Tuples only, unaligned
"-c", query,
)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", s.cfg.Password))
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to list databases: %w", err)
}
// Parse output
lines := strings.Split(strings.TrimSpace(string(output)), "\n")
databases := []string{}
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" {
databases = append(databases, line)
}
}
return databases, nil
}
// listMySQLUserDatabases lists MySQL/MariaDB user databases
func (s *Safety) listMySQLUserDatabases(ctx context.Context) ([]string, error) {
// Exclude system databases
query := "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys') ORDER BY SCHEMA_NAME"
cmd := exec.CommandContext(ctx,
"mysql",
"-h", s.cfg.Host,
"-P", fmt.Sprintf("%d", s.cfg.Port),
"-u", s.cfg.User,
"-N", // Skip column names
"-e", query,
)
if s.cfg.Password != "" {
cmd.Env = append(os.Environ(), fmt.Sprintf("MYSQL_PWD=%s", s.cfg.Password))
}
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to list databases: %w", err)
}
// Parse output
lines := strings.Split(strings.TrimSpace(string(output)), "\n")
databases := []string{}
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" {
databases = append(databases, line)
}
}
return databases, nil
}