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
+4 -3
View File
@@ -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(),
},
+1 -1
View File
@@ -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),
+3 -3
View File
@@ -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,
"",
+14 -15
View File
@@ -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",
},
+3 -3
View File
@@ -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)
+3 -2
View File
@@ -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)
+3 -3
View File
@@ -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 {
+12 -12
View File
@@ -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)
+4 -4
View File
@@ -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 {
+4 -4
View File
@@ -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,
},