Fix: Database listing now works with peer authentication

Issue: Interactive cluster restore preview showed 'Cannot list databases: exit status 2'
when trying to detect existing databases. This happened because the safety check
functions always used '-h hostname' flag with psql, which breaks peer authentication.

Root cause:
- listPostgresUserDatabases() and checkPostgresDatabaseExists() always included -h flag
- For localhost peer auth, psql should connect via Unix socket (no -h flag)
- Adding -h localhost forces TCP connection which fails with peer authentication

Solution: Match the pattern used throughout the codebase:
- Only add -h flag when host is NOT localhost/127.0.0.1/empty
- For localhost, skip -h flag to use Unix socket
- Set PGPASSWORD only if password is provided

Fixed functions in internal/restore/safety.go:
- listPostgresUserDatabases()
- checkPostgresDatabaseExists()

Now interactive mode correctly shows existing databases count and list when
running as postgres user with peer authentication.
This commit is contained in:
2025-11-12 08:43:16 +00:00
parent 6239e57a20
commit 98f483ae11

View File

@@ -297,16 +297,24 @@ func (s *Safety) CheckDatabaseExists(ctx context.Context, dbName string) (bool,
// checkPostgresDatabaseExists checks if PostgreSQL database exists // checkPostgresDatabaseExists checks if PostgreSQL database exists
func (s *Safety) checkPostgresDatabaseExists(ctx context.Context, dbName string) (bool, error) { func (s *Safety) checkPostgresDatabaseExists(ctx context.Context, dbName string) (bool, error) {
cmd := exec.CommandContext(ctx, args := []string{
"psql",
"-h", s.cfg.Host,
"-p", fmt.Sprintf("%d", s.cfg.Port), "-p", fmt.Sprintf("%d", s.cfg.Port),
"-U", s.cfg.User, "-U", s.cfg.User,
"-d", "postgres", "-d", "postgres",
"-tAc", fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname='%s'", dbName), "-tAc", fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname='%s'", dbName),
) }
// Only add -h flag if host is not localhost (to use Unix socket for peer auth)
if s.cfg.Host != "localhost" && s.cfg.Host != "127.0.0.1" && s.cfg.Host != "" {
args = append([]string{"-h", s.cfg.Host}, args...)
}
cmd := exec.CommandContext(ctx, "psql", args...)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", s.cfg.Password)) // Set password if provided
if s.cfg.Password != "" {
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", s.cfg.Password))
}
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
@@ -354,17 +362,25 @@ func (s *Safety) listPostgresUserDatabases(ctx context.Context) ([]string, error
// Query to get non-template databases excluding 'postgres' system DB // 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" query := "SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres' ORDER BY datname"
cmd := exec.CommandContext(ctx, args := []string{
"psql",
"-h", s.cfg.Host,
"-p", fmt.Sprintf("%d", s.cfg.Port), "-p", fmt.Sprintf("%d", s.cfg.Port),
"-U", s.cfg.User, "-U", s.cfg.User,
"-d", "postgres", "-d", "postgres",
"-tA", // Tuples only, unaligned "-tA", // Tuples only, unaligned
"-c", query, "-c", query,
) }
// Only add -h flag if host is not localhost (to use Unix socket for peer auth)
if s.cfg.Host != "localhost" && s.cfg.Host != "127.0.0.1" && s.cfg.Host != "" {
args = append([]string{"-h", s.cfg.Host}, args...)
}
cmd := exec.CommandContext(ctx, "psql", args...)
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", s.cfg.Password)) // Set password if provided
if s.cfg.Password != "" {
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", s.cfg.Password))
}
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {