switch to metav1.Duration for timeout options (#3121)

* switch to metav1.Duration for timeout options
* fix custom config parsing and use safe coalesce
This commit is contained in:
Felix Kunde
2026-06-29 10:32:24 +02:00
committed by GitHub
parent 9030520e24
commit 1227fc2e1c
23 changed files with 214 additions and 218 deletions
+16 -16
View File
@@ -3,33 +3,33 @@ package config
import (
"encoding/json"
"strings"
"time"
"fmt"
"github.com/zalando/postgres-operator/pkg/spec"
"github.com/zalando/postgres-operator/pkg/util/constants"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// CRD describes CustomResourceDefinition specific configuration parameters
type CRD struct {
ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout time.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod time.Duration `name:"resync_period" default:"30m"`
RepairPeriod time.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
CRDCategories []string `name:"crd_categories" default:"all"`
ReadyWaitInterval *metav1.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout *metav1.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod *metav1.Duration `name:"resync_period" default:"30m"`
RepairPeriod *metav1.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
CRDCategories []string `name:"crd_categories" default:"all"`
}
// Resources describes kubernetes resource specific configuration parameters
type Resources struct {
EnableOwnerReferences *bool `name:"enable_owner_references" default:"false"`
ResourceCheckInterval time.Duration `name:"resource_check_interval" default:"3s"`
ResourceCheckTimeout time.Duration `name:"resource_check_timeout" default:"10m"`
PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"`
PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
ResourceCheckInterval *metav1.Duration `name:"resource_check_interval" default:"3s"`
ResourceCheckTimeout *metav1.Duration `name:"resource_check_timeout" default:"10m"`
PodLabelWaitTimeout *metav1.Duration `name:"pod_label_wait_timeout" default:"10m"`
PodDeletionWaitTimeout *metav1.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
PodTerminateGracePeriod *metav1.Duration `name:"pod_terminate_grace_period" default:"5m"`
LivenessProbe *v1.Probe `name:"-"`
SpiloRunAsUser *int64 `name:"spilo_runasuser"`
SpiloRunAsGroup *int64 `name:"spilo_runasgroup"`
@@ -188,7 +188,7 @@ type Config struct {
// value of this string must be valid JSON or YAML; see initPodServiceAccount
PodServiceAccountDefinition string `name:"pod_service_account_definition" default:""`
PodServiceAccountRoleBindingDefinition string `name:"pod_service_account_role_binding_definition" default:""`
MasterPodMoveTimeout time.Duration `name:"master_pod_move_timeout" default:"20m"`
MasterPodMoveTimeout *metav1.Duration `name:"master_pod_move_timeout" default:"20m"`
DbHostedZone string `name:"db_hosted_zone" default:"db.example.com"`
AWSRegion string `name:"aws_region" default:"eu-central-1"`
WALES3Bucket string `name:"wal_s3_bucket"`
@@ -242,7 +242,7 @@ type Config struct {
RingLogLines int `name:"ring_log_lines" default:"100"`
ClusterHistoryEntries int `name:"cluster_history_entries" default:"1000"`
TeamAPIRoleConfiguration map[string]string `name:"team_api_role_configuration" default:"log_statement:all"`
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
PodTerminateGracePeriod *metav1.Duration `name:"pod_terminate_grace_period" default:"5m"`
PodManagementPolicy string `name:"pod_management_policy" default:"ordered_ready"`
EnableReadinessProbe bool `name:"enable_readiness_probe" default:"false"`
ProtectedRoles []string `name:"protected_role_names" default:"admin,cron_admin"`
@@ -258,8 +258,8 @@ type Config struct {
MajorVersionUpgradeTeamAllowList []string `name:"major_version_upgrade_team_allow_list" default:""`
MinimalMajorVersion string `name:"minimal_major_version" default:"14"`
TargetMajorVersion string `name:"target_major_version" default:"18"`
PatroniAPICheckInterval time.Duration `name:"patroni_api_check_interval" default:"1s"`
PatroniAPICheckTimeout time.Duration `name:"patroni_api_check_timeout" default:"5s"`
PatroniAPICheckInterval *metav1.Duration `name:"patroni_api_check_interval" default:"1s"`
PatroniAPICheckTimeout *metav1.Duration `name:"patroni_api_check_timeout" default:"5s"`
EnablePatroniFailsafeMode *bool `name:"enable_patroni_failsafe_mode" default:"false"`
EnableSecretsDeletion *bool `name:"enable_secrets_deletion" default:"true"`
EnablePersistentVolumeClaimDeletion *bool `name:"enable_persistent_volume_claim_deletion" default:"true"`
+6 -6
View File
@@ -230,16 +230,16 @@ var newFromMapTests = []struct {
{
description: "duration parsing",
input: map[string]string{
"ready_wait_interval": "10s",
"ready_wait_timeout": "1m",
"patroni_api_check_interval": "1s",
"patroni_api_check_timeout": "5s",
},
expectPanic: false,
validateFunc: func(t *testing.T, cfg *Config) {
if cfg.ReadyWaitInterval.Seconds() != 10 {
t.Errorf("expected ReadyWaitInterval=10s, got %v", cfg.ReadyWaitInterval)
if cfg.PatroniAPICheckInterval.Seconds() != 1 {
t.Errorf("expected check interval of 1s, got %.0fs", cfg.PatroniAPICheckInterval.Seconds())
}
if cfg.ReadyWaitTimeout.Minutes() != 1 {
t.Errorf("expected ReadyWaitTimeout=1m, got %v", cfg.ReadyWaitTimeout)
if cfg.PatroniAPICheckTimeout.Seconds() != 5 {
t.Errorf("expected check timeout of 5s, got %.0fs", cfg.PatroniAPICheckTimeout.Seconds())
}
},
},
+12 -7
View File
@@ -7,6 +7,8 @@ import (
"strconv"
"strings"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type decoder interface {
@@ -101,13 +103,7 @@ func processField(value string, field reflect.Value) error {
val int64
err error
)
if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
var d time.Duration
d, err = time.ParseDuration(value)
val = int64(d)
} else {
val, err = strconv.ParseInt(value, 0, typ.Bits())
}
val, err = strconv.ParseInt(value, 0, typ.Bits())
if err != nil {
return err
}
@@ -165,6 +161,15 @@ func processField(value string, field reflect.Value) error {
mp.SetMapIndex(k, v)
}
field.Set(mp)
case reflect.Struct:
if typ.Name() == "Duration" {
var d time.Duration
d, err := time.ParseDuration(value)
if err != nil {
return err
}
field.Set(reflect.ValueOf(metav1.Duration{Duration: d}))
}
}
return nil
+4 -4
View File
@@ -311,14 +311,14 @@ func CoalesceBool(val, defaultVal *bool) *bool {
return val
}
// CoalesceDuration works like coalesce but for time.Duration
func CoalesceDuration(val time.Duration, defaultVal string) time.Duration {
if val == 0 {
// CoalesceDuration works like coalesce but for metav1.Duration
func CoalesceDuration(val *metav1.Duration, defaultVal string) *metav1.Duration {
if val == nil || val.Duration == 0 {
duration, err := time.ParseDuration(defaultVal)
if err != nil {
panic(err)
}
return duration
return &metav1.Duration{Duration: duration}
}
return val
}