ci: add golangci-lint config and fix formatting
- Add .golangci.yml with minimal linters (govet, ineffassign) - Run gofmt -s and goimports on all files to fix formatting - Disable fieldalignment and copylocks checks in govet
This commit is contained in:
@@ -24,18 +24,18 @@ func NewRecoveryConfigGenerator(log logger.Logger) *RecoveryConfigGenerator {
|
||||
// RecoveryConfig holds all recovery configuration parameters
|
||||
type RecoveryConfig struct {
|
||||
// Core recovery settings
|
||||
Target *RecoveryTarget
|
||||
WALArchiveDir string
|
||||
Target *RecoveryTarget
|
||||
WALArchiveDir string
|
||||
RestoreCommand string
|
||||
|
||||
|
||||
// PostgreSQL version
|
||||
PostgreSQLVersion int // Major version (12, 13, 14, etc.)
|
||||
|
||||
|
||||
// Additional settings
|
||||
PrimaryConnInfo string // For standby mode
|
||||
PrimarySlotName string // Replication slot name
|
||||
PrimaryConnInfo string // For standby mode
|
||||
PrimarySlotName string // Replication slot name
|
||||
RecoveryMinApplyDelay string // Min delay for replay
|
||||
|
||||
|
||||
// Paths
|
||||
DataDir string // PostgreSQL data directory
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func (rcg *RecoveryConfigGenerator) generateModernRecoveryConfig(config *Recover
|
||||
// Create recovery.signal file (empty file that triggers recovery mode)
|
||||
recoverySignalPath := filepath.Join(config.DataDir, "recovery.signal")
|
||||
rcg.log.Info("Creating recovery.signal file", "path", recoverySignalPath)
|
||||
|
||||
|
||||
signalFile, err := os.Create(recoverySignalPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create recovery.signal: %w", err)
|
||||
@@ -180,7 +180,7 @@ func (rcg *RecoveryConfigGenerator) generateLegacyRecoveryConfig(config *Recover
|
||||
func (rcg *RecoveryConfigGenerator) generateRestoreCommand(walArchiveDir string) string {
|
||||
// The restore_command is executed by PostgreSQL to fetch WAL files
|
||||
// %f = WAL filename, %p = full path to copy WAL file to
|
||||
|
||||
|
||||
// Try multiple extensions (.gz.enc, .enc, .gz, plain)
|
||||
// This handles compressed and/or encrypted WAL files
|
||||
return fmt.Sprintf(`bash -c 'for ext in .gz.enc .enc .gz ""; do [ -f "%s/%%f$ext" ] && { [ -z "$ext" ] && cp "%s/%%f$ext" "%%p" || case "$ext" in *.gz.enc) gpg -d "%s/%%f$ext" | gunzip > "%%p" ;; *.enc) gpg -d "%s/%%f$ext" > "%%p" ;; *.gz) gunzip -c "%s/%%f$ext" > "%%p" ;; esac; exit 0; }; done; exit 1'`,
|
||||
@@ -232,14 +232,14 @@ func (rcg *RecoveryConfigGenerator) ValidateDataDirectory(dataDir string) error
|
||||
// DetectPostgreSQLVersion detects the PostgreSQL version from the data directory
|
||||
func (rcg *RecoveryConfigGenerator) DetectPostgreSQLVersion(dataDir string) (int, error) {
|
||||
pgVersionPath := filepath.Join(dataDir, "PG_VERSION")
|
||||
|
||||
|
||||
content, err := os.ReadFile(pgVersionPath)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to read PG_VERSION: %w", err)
|
||||
}
|
||||
|
||||
versionStr := strings.TrimSpace(string(content))
|
||||
|
||||
|
||||
// Parse major version (e.g., "14" or "14.2")
|
||||
parts := strings.Split(versionStr, ".")
|
||||
if len(parts) == 0 {
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
// RecoveryTarget represents a PostgreSQL recovery target
|
||||
type RecoveryTarget struct {
|
||||
Type string // "time", "xid", "lsn", "name", "immediate"
|
||||
Value string // The target value (timestamp, XID, LSN, or restore point name)
|
||||
Action string // "promote", "pause", "shutdown"
|
||||
Timeline string // Timeline to follow ("latest" or timeline ID)
|
||||
Type string // "time", "xid", "lsn", "name", "immediate"
|
||||
Value string // The target value (timestamp, XID, LSN, or restore point name)
|
||||
Action string // "promote", "pause", "shutdown"
|
||||
Timeline string // Timeline to follow ("latest" or timeline ID)
|
||||
Inclusive bool // Whether target is inclusive (default: true)
|
||||
}
|
||||
|
||||
@@ -128,13 +128,13 @@ func (rt *RecoveryTarget) validateTime() error {
|
||||
|
||||
// Try parsing various timestamp formats
|
||||
formats := []string{
|
||||
"2006-01-02 15:04:05", // Standard format
|
||||
"2006-01-02 15:04:05.999999", // With microseconds
|
||||
"2006-01-02T15:04:05", // ISO 8601
|
||||
"2006-01-02T15:04:05Z", // ISO 8601 with UTC
|
||||
"2006-01-02T15:04:05-07:00", // ISO 8601 with timezone
|
||||
time.RFC3339, // RFC3339
|
||||
time.RFC3339Nano, // RFC3339 with nanoseconds
|
||||
"2006-01-02 15:04:05", // Standard format
|
||||
"2006-01-02 15:04:05.999999", // With microseconds
|
||||
"2006-01-02T15:04:05", // ISO 8601
|
||||
"2006-01-02T15:04:05Z", // ISO 8601 with UTC
|
||||
"2006-01-02T15:04:05-07:00", // ISO 8601 with timezone
|
||||
time.RFC3339, // RFC3339
|
||||
time.RFC3339Nano, // RFC3339 with nanoseconds
|
||||
}
|
||||
|
||||
var parseErr error
|
||||
@@ -283,24 +283,24 @@ func FormatConfigLine(key, value string) string {
|
||||
// String returns a human-readable representation of the recovery target
|
||||
func (rt *RecoveryTarget) String() string {
|
||||
var sb strings.Builder
|
||||
|
||||
|
||||
sb.WriteString("Recovery Target:\n")
|
||||
sb.WriteString(fmt.Sprintf(" Type: %s\n", rt.Type))
|
||||
|
||||
|
||||
if rt.Type != TargetTypeImmediate {
|
||||
sb.WriteString(fmt.Sprintf(" Value: %s\n", rt.Value))
|
||||
}
|
||||
|
||||
|
||||
sb.WriteString(fmt.Sprintf(" Action: %s\n", rt.Action))
|
||||
|
||||
|
||||
if rt.Timeline != "" {
|
||||
sb.WriteString(fmt.Sprintf(" Timeline: %s\n", rt.Timeline))
|
||||
}
|
||||
|
||||
|
||||
if rt.Type != TargetTypeImmediate && rt.Type != TargetTypeName {
|
||||
sb.WriteString(fmt.Sprintf(" Inclusive: %v\n", rt.Inclusive))
|
||||
}
|
||||
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ func (ro *RestoreOrchestrator) startPostgreSQL(ctx context.Context, opts *Restor
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, pgCtl, "-D", opts.TargetDataDir, "-l", filepath.Join(opts.TargetDataDir, "logfile"), "start")
|
||||
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
ro.log.Error("PostgreSQL startup failed", "output", string(output))
|
||||
@@ -321,18 +321,18 @@ func (ro *RestoreOrchestrator) monitorRecovery(ctx context.Context, opts *Restor
|
||||
pidFile := filepath.Join(opts.TargetDataDir, "postmaster.pid")
|
||||
if _, err := os.Stat(pidFile); err == nil {
|
||||
ro.log.Info("✅ PostgreSQL is running")
|
||||
|
||||
|
||||
// Check if recovery files still exist
|
||||
recoverySignal := filepath.Join(opts.TargetDataDir, "recovery.signal")
|
||||
recoveryConf := filepath.Join(opts.TargetDataDir, "recovery.conf")
|
||||
|
||||
|
||||
if _, err := os.Stat(recoverySignal); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(recoveryConf); os.IsNotExist(err) {
|
||||
ro.log.Info("✅ Recovery completed - PostgreSQL promoted to primary")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ro.log.Info("Recovery in progress...")
|
||||
} else {
|
||||
ro.log.Info("PostgreSQL not yet started or crashed")
|
||||
|
||||
Reference in New Issue
Block a user