Fix: Critical bug - cluster restore showing success with 0 databases restored
CRITICAL FIXES: - Add check for successCount == 0 to properly fail when no databases restored - Fix tryRestartPostgreSQL to use non-interactive sudo (-n flag) - Add 10-second timeout per restart attempt to prevent blocking - Try pg_ctl directly for postgres user (no sudo needed) - Set stdin to nil to prevent sudo from waiting for password input This fixes the issue where cluster restore showed success but no databases were actually restored due to sudo blocking on password prompts.
This commit is contained in:
@@ -4,8 +4,8 @@ This directory contains pre-compiled binaries for the DB Backup Tool across mult
|
|||||||
|
|
||||||
## Build Information
|
## Build Information
|
||||||
- **Version**: 3.42.34
|
- **Version**: 3.42.34
|
||||||
- **Build Time**: 2026-01-16_12:38:18_UTC
|
- **Build Time**: 2026-01-16_12:52:56_UTC
|
||||||
- **Git Commit**: 510175f
|
- **Git Commit**: 62ddc57
|
||||||
|
|
||||||
## Recent Updates (v1.1.0)
|
## Recent Updates (v1.1.0)
|
||||||
- ✅ Fixed TUI progress display with line-by-line output
|
- ✅ Fixed TUI progress display with line-by-line output
|
||||||
|
|||||||
@@ -1201,6 +1201,17 @@ func (e *Engine) RestoreCluster(ctx context.Context, archivePath string) error {
|
|||||||
successCountFinal := int(atomic.LoadInt32(&successCount))
|
successCountFinal := int(atomic.LoadInt32(&successCount))
|
||||||
failCountFinal := int(atomic.LoadInt32(&failCount))
|
failCountFinal := int(atomic.LoadInt32(&failCount))
|
||||||
|
|
||||||
|
// CRITICAL: Check if no databases were restored at all
|
||||||
|
if successCountFinal == 0 {
|
||||||
|
e.progress.Fail(fmt.Sprintf("Cluster restore FAILED: 0 of %d databases restored", totalDBs))
|
||||||
|
operation.Fail("No databases were restored")
|
||||||
|
|
||||||
|
if failCountFinal > 0 && restoreErrors != nil {
|
||||||
|
return fmt.Errorf("cluster restore failed: all %d database(s) failed:\n%s", failCountFinal, restoreErrors.Error())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("cluster restore failed: no databases were restored (0 of %d total). Check PostgreSQL logs for details", totalDBs)
|
||||||
|
}
|
||||||
|
|
||||||
if failCountFinal > 0 {
|
if failCountFinal > 0 {
|
||||||
// Format multi-error with detailed output
|
// Format multi-error with detailed output
|
||||||
restoreErrors.ErrorFormat = func(errs []error) string {
|
restoreErrors.ErrorFormat = func(errs []error) string {
|
||||||
@@ -2058,36 +2069,43 @@ func (e *Engine) boostPostgreSQLSettings(ctx context.Context, lockBoostValue int
|
|||||||
|
|
||||||
// tryRestartPostgreSQL attempts to restart PostgreSQL using various methods
|
// tryRestartPostgreSQL attempts to restart PostgreSQL using various methods
|
||||||
// Returns true if restart was successful
|
// Returns true if restart was successful
|
||||||
|
// IMPORTANT: Uses short timeouts and non-interactive sudo to avoid blocking on password prompts
|
||||||
func (e *Engine) tryRestartPostgreSQL(ctx context.Context) bool {
|
func (e *Engine) tryRestartPostgreSQL(ctx context.Context) bool {
|
||||||
e.progress.Update("Attempting PostgreSQL restart for lock settings...")
|
e.progress.Update("Attempting PostgreSQL restart for lock settings...")
|
||||||
|
|
||||||
// Method 1: systemctl (most common on modern Linux)
|
// Use short timeout for each restart attempt (don't block on sudo password prompts)
|
||||||
cmd := exec.CommandContext(ctx, "sudo", "systemctl", "restart", "postgresql")
|
runWithTimeout := func(args ...string) bool {
|
||||||
if err := cmd.Run(); err == nil {
|
cmdCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.CommandContext(cmdCtx, args[0], args[1:]...)
|
||||||
|
// Set stdin to /dev/null to prevent sudo from waiting for password
|
||||||
|
cmd.Stdin = nil
|
||||||
|
return cmd.Run() == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 1: systemctl (most common on modern Linux) - use sudo -n for non-interactive
|
||||||
|
if runWithTimeout("sudo", "-n", "systemctl", "restart", "postgresql") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 2: systemctl with version suffix (e.g., postgresql-15)
|
// Method 2: systemctl with version suffix (e.g., postgresql-15)
|
||||||
for _, ver := range []string{"17", "16", "15", "14", "13", "12"} {
|
for _, ver := range []string{"17", "16", "15", "14", "13", "12"} {
|
||||||
cmd = exec.CommandContext(ctx, "sudo", "systemctl", "restart", "postgresql-"+ver)
|
if runWithTimeout("sudo", "-n", "systemctl", "restart", "postgresql-"+ver) {
|
||||||
if err := cmd.Run(); err == nil {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 3: service command (older systems)
|
// Method 3: service command (older systems)
|
||||||
cmd = exec.CommandContext(ctx, "sudo", "service", "postgresql", "restart")
|
if runWithTimeout("sudo", "-n", "service", "postgresql", "restart") {
|
||||||
if err := cmd.Run(); err == nil {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 4: pg_ctl as postgres user
|
// Method 4: pg_ctl as postgres user (if we ARE postgres user, no sudo needed)
|
||||||
cmd = exec.CommandContext(ctx, "sudo", "-u", "postgres", "pg_ctl", "restart", "-D", "/var/lib/postgresql/data", "-m", "fast")
|
if runWithTimeout("pg_ctl", "restart", "-D", "/var/lib/postgresql/data", "-m", "fast") {
|
||||||
if err := cmd.Run(); err == nil {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method 5: Try common PGDATA paths
|
// Method 5: Try common PGDATA paths with pg_ctl directly (for postgres user)
|
||||||
pgdataPaths := []string{
|
pgdataPaths := []string{
|
||||||
"/var/lib/pgsql/data",
|
"/var/lib/pgsql/data",
|
||||||
"/var/lib/pgsql/17/data",
|
"/var/lib/pgsql/17/data",
|
||||||
@@ -2098,8 +2116,7 @@ func (e *Engine) tryRestartPostgreSQL(ctx context.Context) bool {
|
|||||||
"/var/lib/postgresql/15/main",
|
"/var/lib/postgresql/15/main",
|
||||||
}
|
}
|
||||||
for _, pgdata := range pgdataPaths {
|
for _, pgdata := range pgdataPaths {
|
||||||
cmd = exec.CommandContext(ctx, "sudo", "-u", "postgres", "pg_ctl", "restart", "-D", pgdata, "-m", "fast")
|
if runWithTimeout("pg_ctl", "restart", "-D", pgdata, "-m", "fast") {
|
||||||
if err := cmd.Run(); err == nil {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user