Skip to content

Commit 3ac6753

Browse files
committed
feat: make startup probe configurable for the sidecar
Signed-off-by: Tudor Golubenco <[email protected]>
1 parent b556fea commit 3ac6753

File tree

4 files changed

+127
-3
lines changed

4 files changed

+127
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
8080

8181
.PHONY: build
8282
build: manifests generate fmt vet ## Build manager binary.
83-
go build -o bin/manager cmd/main.go
83+
go build -o bin/manager cmd/manager/main.go
8484

8585
.PHONY: run
8686
run: manifests generate fmt vet ## Run a controller from your host.

internal/cnpgi/operator/config/config.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"strconv"
45
"strings"
56

67
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
@@ -57,6 +58,29 @@ type PluginConfiguration struct {
5758

5859
ReplicaSourceBarmanObjectName string
5960
ReplicaSourceServerName string
61+
62+
// Probe configuration
63+
StartupProbeConfig *ProbeConfig
64+
}
65+
66+
// ProbeConfig holds configuration for Kubernetes probes
67+
type ProbeConfig struct {
68+
InitialDelaySeconds int32
69+
TimeoutSeconds int32
70+
PeriodSeconds int32
71+
FailureThreshold int32
72+
SuccessThreshold int32
73+
}
74+
75+
// DefaultProbeConfig returns the default probe configuration
76+
func DefaultProbeConfig() *ProbeConfig {
77+
return &ProbeConfig{
78+
InitialDelaySeconds: 0,
79+
TimeoutSeconds: 10,
80+
PeriodSeconds: 10,
81+
FailureThreshold: 10,
82+
SuccessThreshold: 1,
83+
}
6084
}
6185

6286
// GetBarmanObjectKey gets the namespaced name of the barman object
@@ -166,11 +190,50 @@ func NewFromCluster(cluster *cnpgv1.Cluster) *PluginConfiguration {
166190
// used for wal_restore in the designed primary of a replica cluster
167191
ReplicaSourceServerName: replicaSourceServerName,
168192
ReplicaSourceBarmanObjectName: replicaSourceBarmanObjectName,
193+
// probe configuration
194+
StartupProbeConfig: parseProbeConfig(helper.Parameters),
169195
}
170196

171197
return result
172198
}
173199

200+
// parseProbeConfig parses probe configuration from plugin parameters
201+
func parseProbeConfig(parameters map[string]string) *ProbeConfig {
202+
config := DefaultProbeConfig()
203+
204+
if val, ok := parameters["startupProbe.initialDelaySeconds"]; ok {
205+
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
206+
config.InitialDelaySeconds = int32(parsed)
207+
}
208+
}
209+
210+
if val, ok := parameters["startupProbe.timeoutSeconds"]; ok {
211+
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
212+
config.TimeoutSeconds = int32(parsed)
213+
}
214+
}
215+
216+
if val, ok := parameters["startupProbe.periodSeconds"]; ok {
217+
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
218+
config.PeriodSeconds = int32(parsed)
219+
}
220+
}
221+
222+
if val, ok := parameters["startupProbe.failureThreshold"]; ok {
223+
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
224+
config.FailureThreshold = int32(parsed)
225+
}
226+
}
227+
228+
if val, ok := parameters["startupProbe.successThreshold"]; ok {
229+
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
230+
config.SuccessThreshold = int32(parsed)
231+
}
232+
}
233+
234+
return config
235+
}
236+
174237
func getRecoveryParameters(cluster *cnpgv1.Cluster) map[string]string {
175238
recoveryPluginConfiguration := getRecoverySourcePlugin(cluster)
176239
if recoveryPluginConfiguration == nil {

internal/cnpgi/operator/lifecycle.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,15 @@ func (impl LifecycleImplementation) reconcileJob(
129129
env: env,
130130
certificates: certificates,
131131
resources: resources,
132+
probeConfig: pluginConfiguration.StartupProbeConfig,
132133
})
133134
}
134135

135136
type sidecarConfiguration struct {
136137
env []corev1.EnvVar
137138
certificates []corev1.VolumeProjection
138139
resources corev1.ResourceRequirements
140+
probeConfig *config.ProbeConfig
139141
}
140142

141143
func reconcileJob(
@@ -221,6 +223,7 @@ func (impl LifecycleImplementation) reconcilePod(
221223
env: env,
222224
certificates: certificates,
223225
resources: resources,
226+
probeConfig: pluginConfiguration.StartupProbeConfig,
224227
})
225228
}
226229

@@ -304,15 +307,26 @@ func reconcilePodSpec(
304307
envs = append(envs, config.env...)
305308

306309
baseProbe := &corev1.Probe{
307-
FailureThreshold: 10,
308-
TimeoutSeconds: 10,
309310
ProbeHandler: corev1.ProbeHandler{
310311
Exec: &corev1.ExecAction{
311312
Command: []string{"/manager", "healthcheck", "unix"},
312313
},
313314
},
314315
}
315316

317+
// Apply configurable probe settings if available
318+
if config.probeConfig != nil {
319+
baseProbe.InitialDelaySeconds = config.probeConfig.InitialDelaySeconds
320+
baseProbe.TimeoutSeconds = config.probeConfig.TimeoutSeconds
321+
baseProbe.PeriodSeconds = config.probeConfig.PeriodSeconds
322+
baseProbe.FailureThreshold = config.probeConfig.FailureThreshold
323+
baseProbe.SuccessThreshold = config.probeConfig.SuccessThreshold
324+
} else {
325+
// Fallback to default values
326+
baseProbe.FailureThreshold = 10
327+
baseProbe.TimeoutSeconds = 10
328+
}
329+
316330
// fixed values
317331
sidecarTemplate.Name = "plugin-barman-cloud"
318332
sidecarTemplate.Image = viper.GetString("sidecar-image")

internal/cnpgi/operator/lifecycle_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,53 @@ var _ = Describe("LifecycleImplementation", func() {
172172
})
173173

174174
Describe("reconcilePod", func() {
175+
It("returns a patch for a valid pod with probe configuration", func(ctx SpecContext) {
176+
// Configure plugin with custom probe settings
177+
pluginConfiguration.StartupProbeConfig = &config.ProbeConfig{
178+
InitialDelaySeconds: 1,
179+
TimeoutSeconds: 15,
180+
PeriodSeconds: 2,
181+
FailureThreshold: 5,
182+
SuccessThreshold: 1,
183+
}
184+
185+
pod := &corev1.Pod{
186+
TypeMeta: podTypeMeta,
187+
ObjectMeta: metav1.ObjectMeta{
188+
Name: "test-pod",
189+
},
190+
Spec: corev1.PodSpec{
191+
Containers: []corev1.Container{
192+
{
193+
Name: "postgres",
194+
},
195+
},
196+
},
197+
}
198+
199+
podJSON, err := json.Marshal(pod)
200+
Expect(err).NotTo(HaveOccurred())
201+
202+
request := &lifecycle.OperatorLifecycleRequest{
203+
ObjectDefinition: podJSON,
204+
}
205+
206+
response, err := reconcilePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{
207+
probeConfig: pluginConfiguration.StartupProbeConfig,
208+
})
209+
Expect(err).NotTo(HaveOccurred())
210+
Expect(response).NotTo(BeNil())
211+
Expect(response.JsonPatch).NotTo(BeEmpty())
212+
213+
// Verify the patch contains the expected probe configuration
214+
Expect(string(response.JsonPatch)).To(ContainSubstring("startupProbe"))
215+
Expect(string(response.JsonPatch)).To(ContainSubstring("\"initialDelaySeconds\":1"))
216+
Expect(string(response.JsonPatch)).To(ContainSubstring("\"timeoutSeconds\":15"))
217+
Expect(string(response.JsonPatch)).To(ContainSubstring("\"periodSeconds\":2"))
218+
Expect(string(response.JsonPatch)).To(ContainSubstring("\"failureThreshold\":5"))
219+
Expect(string(response.JsonPatch)).To(ContainSubstring("\"successThreshold\":1"))
220+
})
221+
175222
It("returns a patch for a valid pod", func(ctx SpecContext) {
176223
pod := &corev1.Pod{
177224
TypeMeta: podTypeMeta,

0 commit comments

Comments
 (0)