diff --git a/Makefile b/Makefile index a351bd34..c09bf2d6 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes .PHONY: build build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go + go build -o bin/manager cmd/manager/main.go .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. diff --git a/api/v1/objectstore_types.go b/api/v1/objectstore_types.go index 5eeadf07..788d7fed 100644 --- a/api/v1/objectstore_types.go +++ b/api/v1/objectstore_types.go @@ -22,6 +22,35 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// ProbeConfig holds configuration for probe timing and thresholds +// This is a subset of the corev1.Probe type, with only the fields that we want to expose as configuration. +type ProbeConfig struct { + // InitialDelaySeconds is the number of seconds after the container has started before startup probes are initiated. + // +kubebuilder:default:=0 + // +optional + InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"` + + // TimeoutSeconds is the number of seconds after which the probe times out. + // +kubebuilder:default:=10 + // +optional + TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"` + + // PeriodSeconds is how often (in seconds) to perform the probe. + // +kubebuilder:default:=10 + // +optional + PeriodSeconds int32 `json:"periodSeconds,omitempty"` + + // SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + // +kubebuilder:default:=1 + // +optional + SuccessThreshold int32 `json:"successThreshold,omitempty"` + + // FailureThreshold is the minimum consecutive failures for the probe to be considered failed. + // +kubebuilder:default:=10 + // +optional + FailureThreshold int32 `json:"failureThreshold,omitempty"` +} + // InstanceSidecarConfiguration defines the configuration for the sidecar that runs in the instance pods. type InstanceSidecarConfiguration struct { // The environment to be explicitly passed to the sidecar @@ -38,6 +67,17 @@ type InstanceSidecarConfiguration struct { // +optional Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // StartupProbe defines the configuration for the startup probe of the sidecar container. + // +optional + StartupProbe *ProbeConfig `json:"startupProbe,omitempty"` + + // LivenessProbe defines the configuration for the liveness probe of the sidecar container. + // +optional + LivenessProbe *ProbeConfig `json:"livenessProbe,omitempty"` + + // ReadinessProbe defines the configuration for the readiness probe of the sidecar container. + // +optional + ReadinessProbe *ProbeConfig `json:"readinessProbe,omitempty"` // AdditionalContainerArgs is an optional list of command-line arguments // to be passed to the sidecar container when it starts. // The provided arguments are appended to the container’s default arguments. diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index a86696b5..2c2e0d64 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -36,6 +36,21 @@ func (in *InstanceSidecarConfiguration) DeepCopyInto(out *InstanceSidecarConfigu } } in.Resources.DeepCopyInto(&out.Resources) + if in.StartupProbe != nil { + in, out := &in.StartupProbe, &out.StartupProbe + *out = new(ProbeConfig) + **out = **in + } + if in.LivenessProbe != nil { + in, out := &in.LivenessProbe, &out.LivenessProbe + *out = new(ProbeConfig) + **out = **in + } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(ProbeConfig) + **out = **in + } if in.AdditionalContainerArgs != nil { in, out := &in.AdditionalContainerArgs, &out.AdditionalContainerArgs *out = make([]string, len(*in)) @@ -151,6 +166,21 @@ func (in *ObjectStoreStatus) DeepCopy() *ObjectStoreStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProbeConfig) DeepCopyInto(out *ProbeConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProbeConfig. +func (in *ProbeConfig) DeepCopy() *ProbeConfig { + if in == nil { + return nil + } + out := new(ProbeConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RecoveryWindow) DeepCopyInto(out *RecoveryWindow) { *out = *in diff --git a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml index 7d12b8c1..e4321424 100644 --- a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml +++ b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.16.1 name: objectstores.barmancloud.cnpg.io spec: group: barmancloud.cnpg.io @@ -562,6 +562,78 @@ spec: - name type: object type: array + livenessProbe: + description: LivenessProbe defines the configuration for the liveness + probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object + readinessProbe: + description: ReadinessProbe defines the configuration for the + readiness probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object logLevel: default: info description: 'The log level for PostgreSQL instances. Valid values @@ -639,6 +711,42 @@ spec: The retentionCheckInterval defines the frequency at which the system checks and enforces retention policies. type: integer + startupProbe: + description: StartupProbe defines the configuration for the startup + probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object type: object retentionPolicy: description: |- diff --git a/hack/examples/minio-store.yaml b/hack/examples/minio-store.yaml index cb9eb655..8ae39015 100644 --- a/hack/examples/minio-store.yaml +++ b/hack/examples/minio-store.yaml @@ -14,6 +14,26 @@ spec: limits: memory: "512Mi" cpu: "500m" + additionalContainerArgs: + - --log-level=debug + startupProbe: + initialDelaySeconds: 1 + timeoutSeconds: 10 + periodSeconds: 1 + failureThreshold: 10 + successThreshold: 1 + livenessProbe: + initialDelaySeconds: 30 + timeoutSeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + initialDelaySeconds: 5 + timeoutSeconds: 5 + periodSeconds: 5 + failureThreshold: 3 + successThreshold: 1 configuration: endpointCA: name: minio-server-tls diff --git a/internal/cnpgi/operator/lifecycle.go b/internal/cnpgi/operator/lifecycle.go index a777aaf8..3d54d44c 100644 --- a/internal/cnpgi/operator/lifecycle.go +++ b/internal/cnpgi/operator/lifecycle.go @@ -126,10 +126,28 @@ func (impl LifecycleImplementation) reconcileJob( return nil, err } + startupProbe, err := impl.collectSidecarStartupProbeForRecoveryJob(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + + livenessProbe, err := impl.collectSidecarLivenessProbeForRecoveryJob(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + + readinessProbe, err := impl.collectSidecarReadinessProbeForRecoveryJob(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + return reconcileJob(ctx, cluster, request, sidecarConfiguration{ - env: env, - certificates: certificates, - resources: resources, + env: env, + certificates: certificates, + resources: resources, + startupProbe: startupProbe, + livenessProbe: livenessProbe, + readinessProbe: readinessProbe, }) } @@ -138,6 +156,9 @@ type sidecarConfiguration struct { certificates []corev1.VolumeProjection resources corev1.ResourceRequirements additionalArgs []string + startupProbe *barmancloudv1.ProbeConfig + livenessProbe *barmancloudv1.ProbeConfig + readinessProbe *barmancloudv1.ProbeConfig } func reconcileJob( @@ -224,10 +245,28 @@ func (impl LifecycleImplementation) reconcilePod( return nil, err } + startupProbe, err := impl.collectSidecarStartupProbeForInstancePod(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + + livenessProbe, err := impl.collectSidecarLivenessProbeForInstancePod(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + + readinessProbe, err := impl.collectSidecarReadinessProbeForInstancePod(ctx, pluginConfiguration) + if err != nil { + return nil, err + } + return reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{ env: env, certificates: certificates, resources: resources, + startupProbe: startupProbe, + livenessProbe: livenessProbe, + readinessProbe: readinessProbe, additionalArgs: additionalArgs, }) } @@ -362,8 +401,6 @@ func reconcilePodSpec( envs = append(envs, config.env...) baseProbe := &corev1.Probe{ - FailureThreshold: 10, - TimeoutSeconds: 10, ProbeHandler: corev1.ProbeHandler{ Exec: &corev1.ExecAction{ Command: []string{"/manager", "healthcheck", "unix"}, @@ -371,11 +408,37 @@ func reconcilePodSpec( }, } + startupProbe := createProbe(baseProbe, config.startupProbe, &barmancloudv1.ProbeConfig{ + FailureThreshold: 10, + TimeoutSeconds: 10, + InitialDelaySeconds: 0, + SuccessThreshold: 1, + PeriodSeconds: 10, + }) + + livenessProbe := createProbe(baseProbe, config.livenessProbe, &barmancloudv1.ProbeConfig{ + FailureThreshold: 3, + TimeoutSeconds: 10, + InitialDelaySeconds: 0, + SuccessThreshold: 1, + PeriodSeconds: 10, + }) + + readinessProbe := createProbe(baseProbe, config.readinessProbe, &barmancloudv1.ProbeConfig{ + FailureThreshold: 3, + TimeoutSeconds: 10, + InitialDelaySeconds: 0, + SuccessThreshold: 1, + PeriodSeconds: 10, + }) + // fixed values sidecarTemplate.Name = "plugin-barman-cloud" sidecarTemplate.Image = viper.GetString("sidecar-image") sidecarTemplate.ImagePullPolicy = cluster.Spec.ImagePullPolicy - sidecarTemplate.StartupProbe = baseProbe.DeepCopy() + sidecarTemplate.StartupProbe = startupProbe + sidecarTemplate.LivenessProbe = livenessProbe + sidecarTemplate.ReadinessProbe = readinessProbe sidecarTemplate.SecurityContext = &corev1.SecurityContext{ AllowPrivilegeEscalation: ptr.To(false), RunAsNonRoot: ptr.To(true), @@ -600,3 +663,33 @@ func getCNPGJobRole(job *batchv1.Job) string { return "" } + +// createProbe creates a probe using the base probe's handler and applies configuration or default values +func createProbe(baseProbe *corev1.Probe, config *barmancloudv1.ProbeConfig, defaults *barmancloudv1.ProbeConfig) *corev1.Probe { + probe := baseProbe.DeepCopy() + probe.FailureThreshold = defaults.FailureThreshold + probe.TimeoutSeconds = defaults.TimeoutSeconds + probe.InitialDelaySeconds = defaults.InitialDelaySeconds + probe.SuccessThreshold = defaults.SuccessThreshold + probe.PeriodSeconds = defaults.PeriodSeconds + + if config != nil { + if config.InitialDelaySeconds != 0 { + probe.InitialDelaySeconds = config.InitialDelaySeconds + } + if config.TimeoutSeconds != 0 { + probe.TimeoutSeconds = config.TimeoutSeconds + } + if config.PeriodSeconds != 0 { + probe.PeriodSeconds = config.PeriodSeconds + } + if config.SuccessThreshold != 0 { + probe.SuccessThreshold = config.SuccessThreshold + } + if config.FailureThreshold != 0 { + probe.FailureThreshold = config.FailureThreshold + } + } + + return probe +} diff --git a/internal/cnpgi/operator/lifecycle_probes.go b/internal/cnpgi/operator/lifecycle_probes.go new file mode 100644 index 00000000..fc4c345f --- /dev/null +++ b/internal/cnpgi/operator/lifecycle_probes.go @@ -0,0 +1,123 @@ +package operator + +import ( + "context" + + barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" +) + +// probeAccessor is a function type that extracts a specific probe configuration from an ObjectStore +type probeAccessor func(*barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig + +// collectSidecarProbeForRecoveryJob is a generic function to collect probe configurations for recovery jobs +func (impl LifecycleImplementation) collectSidecarProbeForRecoveryJob( + ctx context.Context, + configuration *config.PluginConfiguration, + accessor probeAccessor, +) (*barmancloudv1.ProbeConfig, error) { + if len(configuration.RecoveryBarmanObjectName) > 0 { + var barmanObjectStore barmancloudv1.ObjectStore + if err := impl.Client.Get(ctx, configuration.GetRecoveryBarmanObjectKey(), &barmanObjectStore); err != nil { + return nil, err + } + + return accessor(&barmanObjectStore), nil + } + + return nil, nil +} + +// collectSidecarProbeForInstancePod is a generic function to collect probe configurations for instance pods +func (impl LifecycleImplementation) collectSidecarProbeForInstancePod( + ctx context.Context, + configuration *config.PluginConfiguration, + accessor probeAccessor, + probeType string, +) (*barmancloudv1.ProbeConfig, error) { + if len(configuration.BarmanObjectName) > 0 { + // On a replica cluster that also archives, the designated primary + // will use both the replica source object store and the object store + // of the cluster. + // In this case, we use the cluster object store for configuring + // the probe of the sidecar container. + + var barmanObjectStore barmancloudv1.ObjectStore + if err := impl.Client.Get(ctx, configuration.GetBarmanObjectKey(), &barmanObjectStore); err != nil { + return nil, err + } + + return accessor(&barmanObjectStore), nil + } + + if len(configuration.RecoveryBarmanObjectName) > 0 { + // On a replica cluster that doesn't archive, the designated primary + // uses only the replica source object store. + // In this case, we use the replica source object store for configuring + // the probe of the sidecar container. + var barmanObjectStore barmancloudv1.ObjectStore + if err := impl.Client.Get(ctx, configuration.GetRecoveryBarmanObjectKey(), &barmanObjectStore); err != nil { + return nil, err + } + + return accessor(&barmanObjectStore), nil + } + + return nil, nil +} + +// Specific probe collection methods that use the generic functions + +func (impl LifecycleImplementation) collectSidecarStartupProbeForRecoveryJob( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForRecoveryJob(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.StartupProbe + }) +} + +func (impl LifecycleImplementation) collectSidecarStartupProbeForInstancePod( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForInstancePod(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.StartupProbe + }, "startup") +} + +func (impl LifecycleImplementation) collectSidecarLivenessProbeForRecoveryJob( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForRecoveryJob(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.LivenessProbe + }) +} + +func (impl LifecycleImplementation) collectSidecarLivenessProbeForInstancePod( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForInstancePod(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.LivenessProbe + }, "liveness") +} + +func (impl LifecycleImplementation) collectSidecarReadinessProbeForRecoveryJob( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForRecoveryJob(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.ReadinessProbe + }) +} + +func (impl LifecycleImplementation) collectSidecarReadinessProbeForInstancePod( + ctx context.Context, + configuration *config.PluginConfiguration, +) (*barmancloudv1.ProbeConfig, error) { + return impl.collectSidecarProbeForInstancePod(ctx, configuration, func(store *barmancloudv1.ObjectStore) *barmancloudv1.ProbeConfig { + return store.Spec.InstanceSidecarConfiguration.ReadinessProbe + }, "readiness") +} diff --git a/internal/cnpgi/operator/lifecycle_test.go b/internal/cnpgi/operator/lifecycle_test.go index 48692ffe..454ed059 100644 --- a/internal/cnpgi/operator/lifecycle_test.go +++ b/internal/cnpgi/operator/lifecycle_test.go @@ -13,6 +13,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" + barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" . "github.com/onsi/ginkgo/v2" @@ -196,6 +197,119 @@ var _ = Describe("LifecycleImplementation", func() { }) Describe("reconcileInstancePod", func() { + It("returns a patch for a valid pod with probe configuration", func(ctx SpecContext) { + // Configure sidecar with custom probe settings + startupProbeConfig := &barmancloudv1.ProbeConfig{ + InitialDelaySeconds: 1, + TimeoutSeconds: 15, + PeriodSeconds: 2, + FailureThreshold: 5, + SuccessThreshold: 1, + } + + pod := &corev1.Pod{ + TypeMeta: podTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "postgres", + }, + }, + }, + } + + podJSON, err := json.Marshal(pod) + Expect(err).NotTo(HaveOccurred()) + + request := &lifecycle.OperatorLifecycleRequest{ + ObjectDefinition: podJSON, + } + + response, err := reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{ + startupProbe: startupProbeConfig, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(response).NotTo(BeNil()) + Expect(response.JsonPatch).NotTo(BeEmpty()) + + // Verify the patch contains the expected probe configuration + Expect(string(response.JsonPatch)).To(ContainSubstring("startupProbe")) + Expect(string(response.JsonPatch)).To(ContainSubstring("\"initialDelaySeconds\":1")) + Expect(string(response.JsonPatch)).To(ContainSubstring("\"timeoutSeconds\":15")) + Expect(string(response.JsonPatch)).To(ContainSubstring("\"periodSeconds\":2")) + Expect(string(response.JsonPatch)).To(ContainSubstring("\"failureThreshold\":5")) + Expect(string(response.JsonPatch)).To(ContainSubstring("\"successThreshold\":1")) + }) + + It("decouples probe configurations - startupProbe doesn't affect other probes", func(ctx SpecContext) { + // Configure only startupProbe with custom settings + startupProbeConfig := &barmancloudv1.ProbeConfig{ + InitialDelaySeconds: 5, + TimeoutSeconds: 20, + PeriodSeconds: 3, + FailureThreshold: 8, + SuccessThreshold: 2, + } + + pod := &corev1.Pod{ + TypeMeta: podTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "postgres", + }, + }, + }, + } + + podJSON, err := json.Marshal(pod) + Expect(err).NotTo(HaveOccurred()) + + request := &lifecycle.OperatorLifecycleRequest{ + ObjectDefinition: podJSON, + } + + response, err := reconcileInstancePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{ + startupProbe: startupProbeConfig, + // livenessProbe and readinessProbe are nil - should use defaults + }) + Expect(err).NotTo(HaveOccurred()) + Expect(response).NotTo(BeNil()) + Expect(response.JsonPatch).NotTo(BeEmpty()) + + patchStr := string(response.JsonPatch) + + // Verify startupProbe has custom settings + Expect(patchStr).To(ContainSubstring("startupProbe")) + Expect(patchStr).To(ContainSubstring("\"initialDelaySeconds\":5")) + Expect(patchStr).To(ContainSubstring("\"timeoutSeconds\":20")) + Expect(patchStr).To(ContainSubstring("\"periodSeconds\":3")) + Expect(patchStr).To(ContainSubstring("\"failureThreshold\":8")) + Expect(patchStr).To(ContainSubstring("\"successThreshold\":2")) + + // Verify livenessProbe has default settings (not affected by startupProbe) + Expect(patchStr).To(ContainSubstring("livenessProbe")) + Expect(patchStr).To(ContainSubstring("\"failureThreshold\":3")) // default for liveness + Expect(patchStr).To(ContainSubstring("\"timeoutSeconds\":10")) // default for liveness + // initialDelaySeconds: 0 is omitted from JSON when it's the zero value + + // Verify readinessProbe has default settings (not affected by startupProbe) + Expect(patchStr).To(ContainSubstring("readinessProbe")) + Expect(patchStr).To(ContainSubstring("\"failureThreshold\":3")) // default for readiness + Expect(patchStr).To(ContainSubstring("\"timeoutSeconds\":10")) // default for readiness + // initialDelaySeconds: 0 is omitted from JSON when it's the zero value + + // Verify that livenessProbe and readinessProbe don't have startupProbe values + Expect(patchStr).NotTo(MatchRegexp(`"livenessProbe"[^}]*"initialDelaySeconds":5`)) + Expect(patchStr).NotTo(MatchRegexp(`"readinessProbe"[^}]*"initialDelaySeconds":5`)) + }) + It("returns a patch for a valid pod", func(ctx SpecContext) { pod := &corev1.Pod{ TypeMeta: podTypeMeta, diff --git a/manifest.yaml b/manifest.yaml index f2d601df..09f14e02 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -561,6 +561,78 @@ spec: - name type: object type: array + livenessProbe: + description: LivenessProbe defines the configuration for the liveness + probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object + readinessProbe: + description: ReadinessProbe defines the configuration for the + readiness probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object logLevel: default: info description: 'The log level for PostgreSQL instances. Valid values @@ -638,6 +710,42 @@ spec: The retentionCheckInterval defines the frequency at which the system checks and enforces retention policies. type: integer + startupProbe: + description: StartupProbe defines the configuration for the startup + probe of the sidecar container. + properties: + failureThreshold: + default: 10 + description: FailureThreshold is the minimum consecutive failures + for the probe to be considered failed. + format: int32 + type: integer + initialDelaySeconds: + default: 0 + description: InitialDelaySeconds is the number of seconds + after the container has started before startup probes are + initiated. + format: int32 + type: integer + periodSeconds: + default: 10 + description: PeriodSeconds is how often (in seconds) to perform + the probe. + format: int32 + type: integer + successThreshold: + default: 1 + description: SuccessThreshold is the minimum consecutive successes + for the probe to be considered successful. + format: int32 + type: integer + timeoutSeconds: + default: 10 + description: TimeoutSeconds is the number of seconds after + which the probe times out. + format: int32 + type: integer + type: object type: object retentionPolicy: description: |-