diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index 19d957431..9cd6b27b7 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -447,8 +447,7 @@ spec: default: 20m description: timeout for successful migration of master pods from unschedulable node - format: int64 - type: integer + type: string node_readiness_label: additionalProperties: type: string @@ -521,8 +520,7 @@ spec: default: 5m description: Postgres pods are terminated forcefully after this timeout - format: int64 - type: integer + type: string secret_name_template: default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}' description: |- @@ -783,13 +781,11 @@ spec: repair_period: default: 5m description: period between consecutive repair requests - format: int64 - type: integer + type: string resync_period: default: 30m description: period between consecutive sync requests - format: int64 - type: integer + type: string scalyr: description: ScalyrConfiguration defines the configuration for ScalyrAPI properties: @@ -885,48 +881,40 @@ spec: default: 1s description: interval between consecutive attempts of operator calling the Patroni API - format: int64 - type: integer + type: string patroni_api_check_timeout: default: 5s description: timeout when waiting for successful response from Patroni API - format: int64 - type: integer + type: string pod_deletion_wait_timeout: default: 10m description: timeout when waiting for the Postgres pods to be deleted - format: int64 - type: integer + type: string pod_label_wait_timeout: default: 10m description: timeout when waiting for pod role and cluster labels - format: int64 - type: integer + type: string ready_wait_interval: default: 4s description: interval between consecutive attempts waiting for postgresql CRD to be created - format: int64 - type: integer + type: string ready_wait_timeout: default: 30s description: timeout for the complete postgres CRD creation - format: int64 - type: integer + type: string resource_check_interval: default: 3s description: interval to wait between consecutive attempts to check for some K8s resources - format: int64 - type: integer + type: string resource_check_timeout: default: 10m description: timeout when waiting for the presence of a certain K8s resource - format: int64 - type: integer + type: string type: object users: description: PostgresUsersConfiguration defines the system users of diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 19d957431..9cd6b27b7 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -447,8 +447,7 @@ spec: default: 20m description: timeout for successful migration of master pods from unschedulable node - format: int64 - type: integer + type: string node_readiness_label: additionalProperties: type: string @@ -521,8 +520,7 @@ spec: default: 5m description: Postgres pods are terminated forcefully after this timeout - format: int64 - type: integer + type: string secret_name_template: default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}' description: |- @@ -783,13 +781,11 @@ spec: repair_period: default: 5m description: period between consecutive repair requests - format: int64 - type: integer + type: string resync_period: default: 30m description: period between consecutive sync requests - format: int64 - type: integer + type: string scalyr: description: ScalyrConfiguration defines the configuration for ScalyrAPI properties: @@ -885,48 +881,40 @@ spec: default: 1s description: interval between consecutive attempts of operator calling the Patroni API - format: int64 - type: integer + type: string patroni_api_check_timeout: default: 5s description: timeout when waiting for successful response from Patroni API - format: int64 - type: integer + type: string pod_deletion_wait_timeout: default: 10m description: timeout when waiting for the Postgres pods to be deleted - format: int64 - type: integer + type: string pod_label_wait_timeout: default: 10m description: timeout when waiting for pod role and cluster labels - format: int64 - type: integer + type: string ready_wait_interval: default: 4s description: interval between consecutive attempts waiting for postgresql CRD to be created - format: int64 - type: integer + type: string ready_wait_timeout: default: 30s description: timeout for the complete postgres CRD creation - format: int64 - type: integer + type: string resource_check_interval: default: 3s description: interval to wait between consecutive attempts to check for some K8s resources - format: int64 - type: integer + type: string resource_check_timeout: default: 10m description: timeout when waiting for the presence of a certain K8s resource - format: int64 - type: integer + type: string type: object users: description: PostgresUsersConfiguration defines the system users of diff --git a/pkg/apis/acid.zalan.do/v1/marshal.go b/pkg/apis/acid.zalan.do/v1/marshal.go index 014214fed..ac351bc0d 100644 --- a/pkg/apis/acid.zalan.do/v1/marshal.go +++ b/pkg/apis/acid.zalan.do/v1/marshal.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "strings" - "time" ) type postgresqlCopy Postgresql @@ -120,29 +119,3 @@ func (p *Postgresql) UnmarshalJSON(data []byte) error { return nil } - -// UnmarshalJSON convert to Duration from byte slice of json -func (d *Duration) UnmarshalJSON(b []byte) error { - var ( - v interface{} - err error - ) - if err = json.Unmarshal(b, &v); err != nil { - return err - } - switch val := v.(type) { - case string: - t, err := time.ParseDuration(val) - if err != nil { - return err - } - *d = Duration(t) - return nil - case float64: - t := time.Duration(val) - *d = Duration(t) - return nil - default: - return fmt.Errorf("could not recognize type %T as a valid type to unmarshal to Duration", val) - } -} diff --git a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go index 0d98d487a..27063fd23 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -5,8 +5,6 @@ package v1 import ( "github.com/zalando/postgres-operator/pkg/util/config" - "time" - "github.com/zalando/postgres-operator/pkg/spec" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -78,7 +76,7 @@ type KubernetesMetaConfiguration struct { PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"` // +kubebuilder:default="5m" // Postgres pods are terminated forcefully after this timeout - PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"` + PodTerminateGracePeriod *metav1.Duration `json:"pod_terminate_grace_period,omitempty"` // +optional LivenessProbe *v1.Probe `json:"liveness_probe"` SpiloPrivileged bool `json:"spilo_privileged,omitempty"` @@ -143,9 +141,9 @@ type KubernetesMetaConfiguration struct { PodPriorityClassName string `json:"pod_priority_class_name,omitempty"` // +kubebuilder:default="20m" // timeout for successful migration of master pods from unschedulable node - MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"` - EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"` - PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"` + MasterPodMoveTimeout *metav1.Duration `json:"master_pod_move_timeout,omitempty"` + EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"` + PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"` // +kubebuilder:default="kubernetes.io/hostname" PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"` // +kubebuilder:validation:Enum=ordered_ready;parallel @@ -186,28 +184,28 @@ type PostgresPodResourcesDefaults struct { type OperatorTimeouts struct { // +kubebuilder:default="3s" // interval to wait between consecutive attempts to check for some K8s resources - ResourceCheckInterval Duration `json:"resource_check_interval,omitempty"` + ResourceCheckInterval *metav1.Duration `json:"resource_check_interval,omitempty"` // +kubebuilder:default="10m" // timeout when waiting for the presence of a certain K8s resource - ResourceCheckTimeout Duration `json:"resource_check_timeout,omitempty"` + ResourceCheckTimeout *metav1.Duration `json:"resource_check_timeout,omitempty"` // +kubebuilder:default="10m" // timeout when waiting for pod role and cluster labels - PodLabelWaitTimeout Duration `json:"pod_label_wait_timeout,omitempty"` + PodLabelWaitTimeout *metav1.Duration `json:"pod_label_wait_timeout,omitempty"` // +kubebuilder:default="10m" // timeout when waiting for the Postgres pods to be deleted - PodDeletionWaitTimeout Duration `json:"pod_deletion_wait_timeout,omitempty"` + PodDeletionWaitTimeout *metav1.Duration `json:"pod_deletion_wait_timeout,omitempty"` // +kubebuilder:default="4s" // interval between consecutive attempts waiting for postgresql CRD to be created - ReadyWaitInterval Duration `json:"ready_wait_interval,omitempty"` + ReadyWaitInterval *metav1.Duration `json:"ready_wait_interval,omitempty"` // +kubebuilder:default="30s" // timeout for the complete postgres CRD creation - ReadyWaitTimeout Duration `json:"ready_wait_timeout,omitempty"` + ReadyWaitTimeout *metav1.Duration `json:"ready_wait_timeout,omitempty"` // +kubebuilder:default="1s" // interval between consecutive attempts of operator calling the Patroni API - PatroniAPICheckInterval Duration `json:"patroni_api_check_interval,omitempty"` + PatroniAPICheckInterval *metav1.Duration `json:"patroni_api_check_interval,omitempty"` // +kubebuilder:default="5s" // timeout when waiting for successful response from Patroni API - PatroniAPICheckTimeout Duration `json:"patroni_api_check_timeout,omitempty"` + PatroniAPICheckTimeout *metav1.Duration `json:"patroni_api_check_timeout,omitempty"` } // LoadBalancerConfiguration defines the LB configuration @@ -420,10 +418,10 @@ type OperatorConfigurationData struct { Workers uint32 `json:"workers,omitempty"` // +kubebuilder:default="30m" // period between consecutive sync requests - ResyncPeriod Duration `json:"resync_period,omitempty"` + ResyncPeriod *metav1.Duration `json:"resync_period,omitempty"` // +kubebuilder:default="5m" // period between consecutive repair requests - RepairPeriod Duration `json:"repair_period,omitempty"` + RepairPeriod *metav1.Duration `json:"repair_period,omitempty"` // +kubebuilder:default=true EnableMaintenanceWindows *bool `json:"enable_maintenance_windows,omitempty"` // +kubebuilder:validation:Type=array @@ -478,6 +476,3 @@ type OperatorConfigurationData struct { IgnoreInstanceLimitsAnnotationKey string `json:"ignore_instance_limits_annotation_key,omitempty"` IgnoreResourcesLimitsAnnotationKey string `json:"ignore_resources_limits_annotation_key,omitempty"` } - -// Duration shortens this frequently used name -type Duration time.Duration diff --git a/pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml b/pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml index 19d957431..9cd6b27b7 100644 --- a/pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml +++ b/pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml @@ -447,8 +447,7 @@ spec: default: 20m description: timeout for successful migration of master pods from unschedulable node - format: int64 - type: integer + type: string node_readiness_label: additionalProperties: type: string @@ -521,8 +520,7 @@ spec: default: 5m description: Postgres pods are terminated forcefully after this timeout - format: int64 - type: integer + type: string secret_name_template: default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}' description: |- @@ -783,13 +781,11 @@ spec: repair_period: default: 5m description: period between consecutive repair requests - format: int64 - type: integer + type: string resync_period: default: 30m description: period between consecutive sync requests - format: int64 - type: integer + type: string scalyr: description: ScalyrConfiguration defines the configuration for ScalyrAPI properties: @@ -885,48 +881,40 @@ spec: default: 1s description: interval between consecutive attempts of operator calling the Patroni API - format: int64 - type: integer + type: string patroni_api_check_timeout: default: 5s description: timeout when waiting for successful response from Patroni API - format: int64 - type: integer + type: string pod_deletion_wait_timeout: default: 10m description: timeout when waiting for the Postgres pods to be deleted - format: int64 - type: integer + type: string pod_label_wait_timeout: default: 10m description: timeout when waiting for pod role and cluster labels - format: int64 - type: integer + type: string ready_wait_interval: default: 4s description: interval between consecutive attempts waiting for postgresql CRD to be created - format: int64 - type: integer + type: string ready_wait_timeout: default: 30s description: timeout for the complete postgres CRD creation - format: int64 - type: integer + type: string resource_check_interval: default: 3s description: interval to wait between consecutive attempts to check for some K8s resources - format: int64 - type: integer + type: string resource_check_timeout: default: 10m description: timeout when waiting for the presence of a certain K8s resource - format: int64 - type: integer + type: string type: object users: description: PostgresUsersConfiguration defines the system users of diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 4fd9c4a00..ddccccf7f 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -163,6 +163,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura *out = new(bool) **out = **in } + if in.PodTerminateGracePeriod != nil { + in, out := &in.PodTerminateGracePeriod, &out.PodTerminateGracePeriod + *out = new(metav1.Duration) + **out = **in + } if in.LivenessProbe != nil { in, out := &in.LivenessProbe, &out.LivenessProbe *out = new(corev1.Probe) @@ -280,6 +285,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura } } out.PodEnvironmentConfigMap = in.PodEnvironmentConfigMap + if in.MasterPodMoveTimeout != nil { + in, out := &in.MasterPodMoveTimeout, &out.MasterPodMoveTimeout + *out = new(metav1.Duration) + **out = **in + } if in.PersistentVolumeClaimRetentionPolicy != nil { in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy *out = make(map[string]string, len(*in)) @@ -433,6 +443,16 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData *out = make([]string, len(*in)) copy(*out, *in) } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(metav1.Duration) + **out = **in + } + if in.RepairPeriod != nil { + in, out := &in.RepairPeriod, &out.RepairPeriod + *out = new(metav1.Duration) + **out = **in + } if in.EnableMaintenanceWindows != nil { in, out := &in.EnableMaintenanceWindows, &out.EnableMaintenanceWindows *out = new(bool) @@ -466,7 +486,7 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData in.MajorVersionUpgrade.DeepCopyInto(&out.MajorVersionUpgrade) in.Kubernetes.DeepCopyInto(&out.Kubernetes) out.PostgresPodResources = in.PostgresPodResources - out.Timeouts = in.Timeouts + in.Timeouts.DeepCopyInto(&out.Timeouts) in.LoadBalancer.DeepCopyInto(&out.LoadBalancer) out.AWSGCP = in.AWSGCP in.OperatorDebug.DeepCopyInto(&out.OperatorDebug) @@ -582,6 +602,46 @@ func (in *OperatorLogicalBackupConfiguration) DeepCopy() *OperatorLogicalBackupC // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OperatorTimeouts) DeepCopyInto(out *OperatorTimeouts) { *out = *in + if in.ResourceCheckInterval != nil { + in, out := &in.ResourceCheckInterval, &out.ResourceCheckInterval + *out = new(metav1.Duration) + **out = **in + } + if in.ResourceCheckTimeout != nil { + in, out := &in.ResourceCheckTimeout, &out.ResourceCheckTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.PodLabelWaitTimeout != nil { + in, out := &in.PodLabelWaitTimeout, &out.PodLabelWaitTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.PodDeletionWaitTimeout != nil { + in, out := &in.PodDeletionWaitTimeout, &out.PodDeletionWaitTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.ReadyWaitInterval != nil { + in, out := &in.ReadyWaitInterval, &out.ReadyWaitInterval + *out = new(metav1.Duration) + **out = **in + } + if in.ReadyWaitTimeout != nil { + in, out := &in.ReadyWaitTimeout, &out.ReadyWaitTimeout + *out = new(metav1.Duration) + **out = **in + } + if in.PatroniAPICheckInterval != nil { + in, out := &in.PatroniAPICheckInterval, &out.PatroniAPICheckInterval + *out = new(metav1.Duration) + **out = **in + } + if in.PatroniAPICheckTimeout != nil { + in, out := &in.PatroniAPICheckTimeout, &out.PatroniAPICheckTimeout + *out = new(metav1.Duration) + **out = **in + } return } diff --git a/pkg/cluster/cluster_test.go b/pkg/cluster/cluster_test.go index 95a445ff3..00e69d4d7 100644 --- a/pkg/cluster/cluster_test.go +++ b/pkg/cluster/cluster_test.go @@ -138,7 +138,8 @@ func TestCreate(t *testing.T) { var cluster = New( Config{ OpConfig: config.Config{ - PodManagementPolicy: "ordered_ready", + PodManagementPolicy: "ordered_ready", + PodTerminateGracePeriod: &metav1.Duration{Duration: 600 * time.Second}, Resources: config.Resources{ ClusterLabels: map[string]string{"application": "spilo"}, ClusterNameLabel: "cluster-name", @@ -147,8 +148,8 @@ func TestCreate(t *testing.T) { DefaultMemoryRequest: "300Mi", DefaultMemoryLimit: "300Mi", PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(3), - ResourceCheckTimeout: time.Duration(10), + ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second}, + ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute}, }, EnableFinalizers: util.True(), }, diff --git a/pkg/cluster/connection_pooler.go b/pkg/cluster/connection_pooler.go index 85685774d..61cd9b041 100644 --- a/pkg/cluster/connection_pooler.go +++ b/pkg/cluster/connection_pooler.go @@ -292,7 +292,7 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( if connectionPoolerSpec == nil { connectionPoolerSpec = &acidv1.ConnectionPooler{} } - gracePeriod := int64(c.OpConfig.PodTerminateGracePeriod.Seconds()) + gracePeriod := int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds()) resources, err := c.generateResourceRequirements( connectionPoolerSpec.Resources, makeDefaultConnectionPoolerResources(&c.OpConfig), diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 306185e90..2b05e2c4a 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1165,7 +1165,7 @@ func (c *Cluster) getPodEnvironmentSecretVariables() ([]v1.EnvVar, error) { secret := &v1.Secret{} var notFoundErr error - err := retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + err := retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { var err error secret, err = c.KubeClient.Secrets(c.Namespace).Get( @@ -1498,7 +1498,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef &tolerationSpec, c.nodeAffinity(c.OpConfig.NodeReadinessLabel, spec.NodeAffinity), spec.SchedulerName, - int64(c.OpConfig.PodTerminateGracePeriod.Seconds()), + int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds()), c.OpConfig.PodServiceAccountName, c.OpConfig.KubeIAMRole, effectivePodPriorityClassName, @@ -2431,7 +2431,7 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) { &tolerationsSpec, c.nodeAffinity(c.OpConfig.NodeReadinessLabel, nil), nil, - int64(c.OpConfig.PodTerminateGracePeriod.Seconds()), + int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds()), c.OpConfig.PodServiceAccountName, c.OpConfig.KubeIAMRole, "", diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 8cbecb2fa..3f385b456 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -6,7 +6,6 @@ import ( "reflect" "sort" "testing" - "time" "github.com/stretchr/testify/assert" @@ -361,8 +360,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) { opConfig: config.Config{ Resources: config.Resources{ PodEnvironmentSecret: testPodEnvironmentObjectNotExists, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, }, err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: still failing after %d retries: secret.core %q not found", maxRetries, testPodEnvironmentObjectNotExists), @@ -372,8 +371,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) { opConfig: config.Config{ Resources: config.Resources{ PodEnvironmentSecret: testPodEnvironmentSecretNameAPIError, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, }, err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: Secret PodEnvironmentSecret API error"), @@ -383,8 +382,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) { opConfig: config.Config{ Resources: config.Resources{ PodEnvironmentSecret: testPodEnvironmentSecretName, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, }, envVars: []v1.EnvVar{ @@ -848,8 +847,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) { Name: testPodEnvironmentConfigMapName, }, PodEnvironmentSecret: testPodEnvironmentSecretName, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, }, cloneDescription: &acidv1.CloneDescription{}, @@ -877,8 +876,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) { Name: testPodEnvironmentConfigMapName, }, PodEnvironmentSecret: testPodEnvironmentSecretName, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, }, cloneDescription: &acidv1.CloneDescription{}, @@ -968,8 +967,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) { opConfig: config.Config{ Resources: config.Resources{ PodEnvironmentSecret: testPodEnvironmentSecretName, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, WALES3Bucket: "global-s3-bucket", }, @@ -986,8 +985,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) { opConfig: config.Config{ Resources: config.Resources{ PodEnvironmentSecret: testPodEnvironmentSecretName, - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, }, WALES3Bucket: "global-s3-bucket", }, diff --git a/pkg/cluster/pod.go b/pkg/cluster/pod.go index 6658ba414..c18054aad 100644 --- a/pkg/cluster/pod.go +++ b/pkg/cluster/pod.go @@ -334,7 +334,7 @@ func (c *Cluster) getPatroniConfig(pod *v1.Pod) (acidv1.Patroni, map[string]stri pgParameters map[string]string ) podName := util.NameFromMeta(pod.ObjectMeta) - err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout, + err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration, func() (bool, error) { var err error patroniConfig, pgParameters, err = c.patroni.GetConfig(pod) @@ -355,7 +355,7 @@ func (c *Cluster) getPatroniConfig(pod *v1.Pod) (acidv1.Patroni, map[string]stri func (c *Cluster) getPatroniMemberData(pod *v1.Pod) (patroni.MemberData, error) { var memberData patroni.MemberData - err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout, + err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration, func() (bool, error) { var err error memberData, err = c.patroni.GetMemberData(pod) @@ -506,7 +506,7 @@ func (c *Cluster) getSwitchoverCandidate(master *v1.Pod) (spec.NamespacedName, e candidates := make([]patroni.ClusterMember, 0) syncCandidates := make([]patroni.ClusterMember, 0) - err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout, + err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration, func() (bool, error) { var err error members, err = c.patroni.GetClusterMembers(master) diff --git a/pkg/cluster/pod_test.go b/pkg/cluster/pod_test.go index 6ab3f9207..0eb1791e2 100644 --- a/pkg/cluster/pod_test.go +++ b/pkg/cluster/pod_test.go @@ -16,6 +16,7 @@ import ( "github.com/zalando/postgres-operator/pkg/util/k8sutil" "github.com/zalando/postgres-operator/pkg/util/patroni" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestGetSwitchoverCandidate(t *testing.T) { @@ -28,8 +29,8 @@ func TestGetSwitchoverCandidate(t *testing.T) { var cluster = New( Config{ OpConfig: config.Config{ - PatroniAPICheckInterval: time.Duration(1), - PatroniAPICheckTimeout: time.Duration(5), + PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second}, + PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second}, }, }, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger, eventRecorder) diff --git a/pkg/cluster/resources.go b/pkg/cluster/resources.go index 1fdad3e5e..6053de471 100644 --- a/pkg/cluster/resources.go +++ b/pkg/cluster/resources.go @@ -234,7 +234,7 @@ func (c *Cluster) replaceStatefulSet(newStatefulSet *appsv1.StatefulSet) error { // wait until the statefulset is truly deleted c.logger.Debug("waiting for the statefulset to be deleted") - err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { _, err2 := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Get(context.TODO(), oldStatefulset.Name, metav1.GetOptions{}) if err2 == nil { @@ -550,7 +550,7 @@ func (c *Cluster) deletePrimaryPodDisruptionBudget() error { c.logger.Infof("pod disruption budget %q has been deleted", util.NameFromMeta(c.PrimaryPodDisruptionBudget.ObjectMeta)) c.PrimaryPodDisruptionBudget = nil - err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { _, err2 := c.KubeClient.PodDisruptionBudgets(pdbName.Namespace).Get(context.TODO(), pdbName.Name, metav1.GetOptions{}) if err2 == nil { @@ -588,7 +588,7 @@ func (c *Cluster) deleteCriticalOpPodDisruptionBudget() error { c.logger.Infof("pod disruption budget %q has been deleted", util.NameFromMeta(c.CriticalOpPodDisruptionBudget.ObjectMeta)) c.CriticalOpPodDisruptionBudget = nil - err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { _, err2 := c.KubeClient.PodDisruptionBudgets(pdbName.Namespace).Get(context.TODO(), pdbName.Name, metav1.GetOptions{}) if err2 == nil { diff --git a/pkg/cluster/sync_test.go b/pkg/cluster/sync_test.go index f7d46d427..1d21d1536 100644 --- a/pkg/cluster/sync_test.go +++ b/pkg/cluster/sync_test.go @@ -101,8 +101,8 @@ func TestSyncStatefulSetsAnnotations(t *testing.T) { DefaultMemoryLimit: "300Mi", InheritedAnnotations: []string{inheritedAnnotation}, PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(3), - ResourceCheckTimeout: time.Duration(10), + ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second}, + ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute}, }, }, }, client, pg, logger, eventRecorder) @@ -187,8 +187,8 @@ func TestPodAnnotationsSync(t *testing.T) { var cluster = New( Config{ OpConfig: config.Config{ - PatroniAPICheckInterval: time.Duration(1), - PatroniAPICheckTimeout: time.Duration(5), + PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second}, + PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second}, PodManagementPolicy: "ordered_ready", CustomPodAnnotations: customPodAnnotations, ConnectionPooler: config.ConnectionPooler{ @@ -207,8 +207,8 @@ func TestPodAnnotationsSync(t *testing.T) { DefaultMemoryLimit: "300Mi", MaxInstances: -1, PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(3), - ResourceCheckTimeout: time.Duration(10), + ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second}, + ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute}, }, }, }, client, pg, logger, eventRecorder) @@ -381,8 +381,8 @@ func TestCheckAndSetGlobalPostgreSQLConfiguration(t *testing.T) { DefaultMemoryRequest: "300Mi", DefaultMemoryLimit: "300Mi", PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(3), - ResourceCheckTimeout: time.Duration(10), + ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second}, + ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute}, }, }, }, client, pg, logger, eventRecorder) @@ -694,8 +694,8 @@ func TestSyncStandbyClusterConfiguration(t *testing.T) { var cluster = New( Config{ OpConfig: config.Config{ - PatroniAPICheckInterval: time.Duration(1), - PatroniAPICheckTimeout: time.Duration(5), + PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second}, + PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second}, PodManagementPolicy: "ordered_ready", Resources: config.Resources{ ClusterLabels: map[string]string{"application": applicationLabel}, @@ -707,8 +707,8 @@ func TestSyncStandbyClusterConfiguration(t *testing.T) { MinInstances: int32(-1), MaxInstances: int32(-1), PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(3), - ResourceCheckTimeout: time.Duration(10), + ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second}, + ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute}, }, }, }, client, pg, logger, eventRecorder) diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go index cbcccd16e..c3a9dda31 100644 --- a/pkg/cluster/util.go +++ b/pkg/cluster/util.go @@ -342,7 +342,7 @@ func (c *Cluster) annotationsSet(annotations map[string]string) map[string]strin } func (c *Cluster) waitForPodLabel(podEvents chan PodEvent, stopCh chan struct{}, role *PostgresRole) (*v1.Pod, error) { - timeout := time.After(c.OpConfig.PodLabelWaitTimeout) + timeout := time.After(c.OpConfig.PodLabelWaitTimeout.Duration) for { select { case podEvent := <-podEvents: @@ -364,7 +364,7 @@ func (c *Cluster) waitForPodLabel(podEvents chan PodEvent, stopCh chan struct{}, } func (c *Cluster) waitForPodDeletion(podEvents chan PodEvent) error { - timeout := time.After(c.OpConfig.PodDeletionWaitTimeout) + timeout := time.After(c.OpConfig.PodDeletionWaitTimeout.Duration) for { select { case podEvent := <-podEvents: @@ -378,7 +378,7 @@ func (c *Cluster) waitForPodDeletion(podEvents chan PodEvent) error { } func (c *Cluster) waitStatefulsetReady() error { - return retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + return retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { listOptions := metav1.ListOptions{ LabelSelector: c.labelsSet(false).String(), @@ -428,7 +428,7 @@ func (c *Cluster) _waitPodLabelsReady(anyReplica bool) error { c.logger.Debug("Waiting for any replica pod to become ready") } - err := retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + err := retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration, func() (bool, error) { masterCount := 0 if !anyReplica { diff --git a/pkg/cluster/util_test.go b/pkg/cluster/util_test.go index 8413ca396..0239abf45 100644 --- a/pkg/cluster/util_test.go +++ b/pkg/cluster/util_test.go @@ -297,8 +297,8 @@ func newInheritedAnnotationsCluster(client k8sutil.KubernetesClient) (*Cluster, cluster := New( Config{ OpConfig: config.Config{ - PatroniAPICheckInterval: time.Duration(1), - PatroniAPICheckTimeout: time.Duration(5), + PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second}, + PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second}, KubernetesUseConfigMaps: true, ConnectionPooler: config.ConnectionPooler{ ConnectionPoolerDefaultCPURequest: "100m", @@ -318,8 +318,8 @@ func newInheritedAnnotationsCluster(client k8sutil.KubernetesClient) (*Cluster, DefaultMemoryLimit: "300Mi", InheritedAnnotations: []string{"owned-by"}, PodRoleLabel: "spilo-role", - ResourceCheckInterval: time.Duration(testResourceCheckInterval), - ResourceCheckTimeout: time.Duration(testResourceCheckTimeout), + ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval}, + ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout}, MinInstances: -1, MaxInstances: -1, }, diff --git a/pkg/controller/node.go b/pkg/controller/node.go index 730a9133b..978fda130 100644 --- a/pkg/controller/node.go +++ b/pkg/controller/node.go @@ -152,7 +152,7 @@ func (c *Controller) nodeDelete(obj interface{}) { func (c *Controller) moveMasterPodsOffNode(node *v1.Node) { // retry to move master until configured timeout is reached - err := retryutil.Retry(1*time.Minute, c.opConfig.MasterPodMoveTimeout, + err := retryutil.Retry(1*time.Minute, c.opConfig.MasterPodMoveTimeout.Duration, func() (bool, error) { err := c.attemptToMoveMasterPodsOffNode(node) if err != nil { diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 94ef86d7c..55f1f00d8 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -4,8 +4,6 @@ import ( "context" "fmt" - "time" - acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" "github.com/zalando/postgres-operator/pkg/util" "github.com/zalando/postgres-operator/pkg/util/config" @@ -44,8 +42,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.MaxInstances = fromCRD.MaxInstances result.IgnoreInstanceLimitsAnnotationKey = fromCRD.IgnoreInstanceLimitsAnnotationKey result.IgnoreResourcesLimitsAnnotationKey = fromCRD.IgnoreResourcesLimitsAnnotationKey - result.ResyncPeriod = util.CoalesceDuration(time.Duration(fromCRD.ResyncPeriod), "30m") - result.RepairPeriod = util.CoalesceDuration(time.Duration(fromCRD.RepairPeriod), "5m") + result.ResyncPeriod = util.CoalesceDuration(fromCRD.ResyncPeriod, "30m") + result.RepairPeriod = util.CoalesceDuration(fromCRD.RepairPeriod, "5m") result.SetMemoryRequestToLimit = fromCRD.SetMemoryRequestToLimit result.ShmVolume = util.CoalesceBool(fromCRD.ShmVolume, util.True()) result.SidecarImages = fromCRD.SidecarImages @@ -75,7 +73,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap result.PodEnvironmentSecret = fromCRD.Kubernetes.PodEnvironmentSecret - result.PodTerminateGracePeriod = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod), "5m") + result.PodTerminateGracePeriod = util.CoalesceDuration(fromCRD.Kubernetes.PodTerminateGracePeriod, "5m") result.LivenessProbe = fromCRD.Kubernetes.LivenessProbe result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged result.SpiloAllowPrivilegeEscalation = util.CoalesceBool(fromCRD.Kubernetes.SpiloAllowPrivilegeEscalation, util.True()) @@ -129,7 +127,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.EnableSecretsDeletion = util.CoalesceBool(fromCRD.Kubernetes.EnableSecretsDeletion, util.True()) result.EnablePersistentVolumeClaimDeletion = util.CoalesceBool(fromCRD.Kubernetes.EnablePersistentVolumeClaimDeletion, util.True()) result.EnableReadinessProbe = fromCRD.Kubernetes.EnableReadinessProbe - result.MasterPodMoveTimeout = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.MasterPodMoveTimeout), "10m") + result.MasterPodMoveTimeout = util.CoalesceDuration(fromCRD.Kubernetes.MasterPodMoveTimeout, "10m") result.EnablePodAntiAffinity = fromCRD.Kubernetes.EnablePodAntiAffinity result.PodAntiAffinityTopologyKey = util.Coalesce(fromCRD.Kubernetes.PodAntiAffinityTopologyKey, "kubernetes.io/hostname") result.PodAntiAffinityPreferredDuringScheduling = fromCRD.Kubernetes.PodAntiAffinityPreferredDuringScheduling @@ -146,14 +144,14 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.MaxMemoryRequest = fromCRD.PostgresPodResources.MaxMemoryRequest // timeout config - result.ResourceCheckInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ResourceCheckInterval), "3s") - result.ResourceCheckTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ResourceCheckTimeout), "10m") - result.PodLabelWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PodLabelWaitTimeout), "10m") - result.PodDeletionWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PodDeletionWaitTimeout), "10m") - result.ReadyWaitInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ReadyWaitInterval), "4s") - result.ReadyWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ReadyWaitTimeout), "30s") - result.PatroniAPICheckInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PatroniAPICheckInterval), "1s") - result.PatroniAPICheckTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PatroniAPICheckTimeout), "5s") + result.ResourceCheckInterval = util.CoalesceDuration(fromCRD.Timeouts.ResourceCheckInterval, "3s") + result.ResourceCheckTimeout = util.CoalesceDuration(fromCRD.Timeouts.ResourceCheckTimeout, "10m") + result.PodLabelWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.PodLabelWaitTimeout, "10m") + result.PodDeletionWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.PodDeletionWaitTimeout, "10m") + result.ReadyWaitInterval = util.CoalesceDuration(fromCRD.Timeouts.ReadyWaitInterval, "4s") + result.ReadyWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.ReadyWaitTimeout, "30s") + result.PatroniAPICheckInterval = util.CoalesceDuration(fromCRD.Timeouts.PatroniAPICheckInterval, "1s") + result.PatroniAPICheckTimeout = util.CoalesceDuration(fromCRD.Timeouts.PatroniAPICheckTimeout, "5s") // load balancer config result.DbHostedZone = util.Coalesce(fromCRD.LoadBalancer.DbHostedZone, "db.example.com") diff --git a/pkg/controller/postgresql.go b/pkg/controller/postgresql.go index 0933f7823..942ff9951 100644 --- a/pkg/controller/postgresql.go +++ b/pkg/controller/postgresql.go @@ -27,7 +27,7 @@ import ( func (c *Controller) clusterResync(stopCh <-chan struct{}, wg *sync.WaitGroup) { defer wg.Done() - ticker := time.NewTicker(c.opConfig.ResyncPeriod) + ticker := time.NewTicker(c.opConfig.ResyncPeriod.Duration) for { select { diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 43fa37a33..85119b18b 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -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"` diff --git a/pkg/util/config/config_test.go b/pkg/util/config/config_test.go index c5fd48d93..6373fdc9a 100644 --- a/pkg/util/config/config_test.go +++ b/pkg/util/config/config_test.go @@ -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()) } }, }, diff --git a/pkg/util/config/util.go b/pkg/util/config/util.go index 4c1bdf7e0..ae1deb461 100644 --- a/pkg/util/config/util.go +++ b/pkg/util/config/util.go @@ -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 diff --git a/pkg/util/util.go b/pkg/util/util.go index 993a773c4..79ff52282 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -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 }