mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-01-11 21:23:12 +01:00
feat: make startup probe configurable for the sidecar
Signed-off-by: Tudor Golubenco <tudor@xata.io>
This commit is contained in:
parent
b556fea179
commit
3ac67534d6
2
Makefile
2
Makefile
@ -80,7 +80,7 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: manifests generate fmt vet ## Build manager binary.
|
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
|
.PHONY: run
|
||||||
run: manifests generate fmt vet ## Run a controller from your host.
|
run: manifests generate fmt vet ## Run a controller from your host.
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||||
@ -57,6 +58,29 @@ type PluginConfiguration struct {
|
|||||||
|
|
||||||
ReplicaSourceBarmanObjectName string
|
ReplicaSourceBarmanObjectName string
|
||||||
ReplicaSourceServerName string
|
ReplicaSourceServerName string
|
||||||
|
|
||||||
|
// Probe configuration
|
||||||
|
StartupProbeConfig *ProbeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeConfig holds configuration for Kubernetes probes
|
||||||
|
type ProbeConfig struct {
|
||||||
|
InitialDelaySeconds int32
|
||||||
|
TimeoutSeconds int32
|
||||||
|
PeriodSeconds int32
|
||||||
|
FailureThreshold int32
|
||||||
|
SuccessThreshold int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultProbeConfig returns the default probe configuration
|
||||||
|
func DefaultProbeConfig() *ProbeConfig {
|
||||||
|
return &ProbeConfig{
|
||||||
|
InitialDelaySeconds: 0,
|
||||||
|
TimeoutSeconds: 10,
|
||||||
|
PeriodSeconds: 10,
|
||||||
|
FailureThreshold: 10,
|
||||||
|
SuccessThreshold: 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBarmanObjectKey gets the namespaced name of the barman object
|
// GetBarmanObjectKey gets the namespaced name of the barman object
|
||||||
@ -166,11 +190,50 @@ func NewFromCluster(cluster *cnpgv1.Cluster) *PluginConfiguration {
|
|||||||
// used for wal_restore in the designed primary of a replica cluster
|
// used for wal_restore in the designed primary of a replica cluster
|
||||||
ReplicaSourceServerName: replicaSourceServerName,
|
ReplicaSourceServerName: replicaSourceServerName,
|
||||||
ReplicaSourceBarmanObjectName: replicaSourceBarmanObjectName,
|
ReplicaSourceBarmanObjectName: replicaSourceBarmanObjectName,
|
||||||
|
// probe configuration
|
||||||
|
StartupProbeConfig: parseProbeConfig(helper.Parameters),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseProbeConfig parses probe configuration from plugin parameters
|
||||||
|
func parseProbeConfig(parameters map[string]string) *ProbeConfig {
|
||||||
|
config := DefaultProbeConfig()
|
||||||
|
|
||||||
|
if val, ok := parameters["startupProbe.initialDelaySeconds"]; ok {
|
||||||
|
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
|
||||||
|
config.InitialDelaySeconds = int32(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := parameters["startupProbe.timeoutSeconds"]; ok {
|
||||||
|
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
|
||||||
|
config.TimeoutSeconds = int32(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := parameters["startupProbe.periodSeconds"]; ok {
|
||||||
|
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
|
||||||
|
config.PeriodSeconds = int32(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := parameters["startupProbe.failureThreshold"]; ok {
|
||||||
|
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
|
||||||
|
config.FailureThreshold = int32(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := parameters["startupProbe.successThreshold"]; ok {
|
||||||
|
if parsed, err := strconv.ParseInt(val, 10, 32); err == nil {
|
||||||
|
config.SuccessThreshold = int32(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
func getRecoveryParameters(cluster *cnpgv1.Cluster) map[string]string {
|
func getRecoveryParameters(cluster *cnpgv1.Cluster) map[string]string {
|
||||||
recoveryPluginConfiguration := getRecoverySourcePlugin(cluster)
|
recoveryPluginConfiguration := getRecoverySourcePlugin(cluster)
|
||||||
if recoveryPluginConfiguration == nil {
|
if recoveryPluginConfiguration == nil {
|
||||||
|
|||||||
@ -129,6 +129,7 @@ func (impl LifecycleImplementation) reconcileJob(
|
|||||||
env: env,
|
env: env,
|
||||||
certificates: certificates,
|
certificates: certificates,
|
||||||
resources: resources,
|
resources: resources,
|
||||||
|
probeConfig: pluginConfiguration.StartupProbeConfig,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +137,7 @@ type sidecarConfiguration struct {
|
|||||||
env []corev1.EnvVar
|
env []corev1.EnvVar
|
||||||
certificates []corev1.VolumeProjection
|
certificates []corev1.VolumeProjection
|
||||||
resources corev1.ResourceRequirements
|
resources corev1.ResourceRequirements
|
||||||
|
probeConfig *config.ProbeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func reconcileJob(
|
func reconcileJob(
|
||||||
@ -221,6 +223,7 @@ func (impl LifecycleImplementation) reconcilePod(
|
|||||||
env: env,
|
env: env,
|
||||||
certificates: certificates,
|
certificates: certificates,
|
||||||
resources: resources,
|
resources: resources,
|
||||||
|
probeConfig: pluginConfiguration.StartupProbeConfig,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +307,6 @@ func reconcilePodSpec(
|
|||||||
envs = append(envs, config.env...)
|
envs = append(envs, config.env...)
|
||||||
|
|
||||||
baseProbe := &corev1.Probe{
|
baseProbe := &corev1.Probe{
|
||||||
FailureThreshold: 10,
|
|
||||||
TimeoutSeconds: 10,
|
|
||||||
ProbeHandler: corev1.ProbeHandler{
|
ProbeHandler: corev1.ProbeHandler{
|
||||||
Exec: &corev1.ExecAction{
|
Exec: &corev1.ExecAction{
|
||||||
Command: []string{"/manager", "healthcheck", "unix"},
|
Command: []string{"/manager", "healthcheck", "unix"},
|
||||||
@ -313,6 +314,19 @@ func reconcilePodSpec(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply configurable probe settings if available
|
||||||
|
if config.probeConfig != nil {
|
||||||
|
baseProbe.InitialDelaySeconds = config.probeConfig.InitialDelaySeconds
|
||||||
|
baseProbe.TimeoutSeconds = config.probeConfig.TimeoutSeconds
|
||||||
|
baseProbe.PeriodSeconds = config.probeConfig.PeriodSeconds
|
||||||
|
baseProbe.FailureThreshold = config.probeConfig.FailureThreshold
|
||||||
|
baseProbe.SuccessThreshold = config.probeConfig.SuccessThreshold
|
||||||
|
} else {
|
||||||
|
// Fallback to default values
|
||||||
|
baseProbe.FailureThreshold = 10
|
||||||
|
baseProbe.TimeoutSeconds = 10
|
||||||
|
}
|
||||||
|
|
||||||
// fixed values
|
// fixed values
|
||||||
sidecarTemplate.Name = "plugin-barman-cloud"
|
sidecarTemplate.Name = "plugin-barman-cloud"
|
||||||
sidecarTemplate.Image = viper.GetString("sidecar-image")
|
sidecarTemplate.Image = viper.GetString("sidecar-image")
|
||||||
|
|||||||
@ -172,6 +172,53 @@ var _ = Describe("LifecycleImplementation", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Describe("reconcilePod", func() {
|
Describe("reconcilePod", func() {
|
||||||
|
It("returns a patch for a valid pod with probe configuration", func(ctx SpecContext) {
|
||||||
|
// Configure plugin with custom probe settings
|
||||||
|
pluginConfiguration.StartupProbeConfig = &config.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 := reconcilePod(ctx, cluster, request, pluginConfiguration, sidecarConfiguration{
|
||||||
|
probeConfig: pluginConfiguration.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("returns a patch for a valid pod", func(ctx SpecContext) {
|
It("returns a patch for a valid pod", func(ctx SpecContext) {
|
||||||
pod := &corev1.Pod{
|
pod := &corev1.Pod{
|
||||||
TypeMeta: podTypeMeta,
|
TypeMeta: podTypeMeta,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user