From 7c4fd4ec084fba2774cb690d90c1941ea17a77fe Mon Sep 17 00:00:00 2001 From: Francesco Pantano Date: Mon, 9 Feb 2026 11:42:16 +0100 Subject: [PATCH] Introduce configurable interface for probe management This patch introduces the ProbeOverrides interface that enables service operators to properly configure and tune liveness, readiness and startup probes for their deployments. This implementation provides: - A ProbeConf struct for standardized probe configuration (path, delays, timeouts, periods and failure thresholds) - A ProvbeOverrides interface that allows service operators to extend their API specs and provide a common set of overrides - A CreateProbeSet function that can be called from the service operators as the main entrypoint to generate a set of probes that should be applied to a Pod. With this function operators can either provide a set of overrides or rely on the defaults defined in the service operator. - A ValidateProbes function to validate (mostly on Updates), at webhooks level, the values provided as user input The functions and the interface provided by this patch reduce the amount of duplicated code that should be implemented in the service operators. Jira: OSPRH-26731 Signed-off-by: Francesco Pantano --- modules/common/probes/probes.go | 190 +++++++-- modules/common/probes/probes_test.go | 382 +++++++++++++++++- modules/common/probes/types.go | 107 +++++ .../common/probes/zz_generated.deepcopy.go | 100 +++++ 4 files changed, 719 insertions(+), 60 deletions(-) create mode 100644 modules/common/probes/types.go create mode 100644 modules/common/probes/zz_generated.deepcopy.go diff --git a/modules/common/probes/probes.go b/modules/common/probes/probes.go index ef34f836..e2d36271 100644 --- a/modules/common/probes/probes.go +++ b/modules/common/probes/probes.go @@ -13,8 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +// +kubebuilder:object:generate:=true + +// The probes package provides utilities for configuring Kubernetes liveness +// and readiness probes -// Package probes provides utilities for configuring Kubernetes liveness and readiness probes package probes import ( @@ -23,61 +26,172 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/util" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/validation/field" + "strings" ) -// ProbeConfig - the configuration for liveness and readiness probes -// LivenessPath - Endpoint path for the liveness probe -// ReadinessPath - Endpoint path for the readiness probe -// InitialDelaySeconds - Number of seconds after the container starts before liveness/readiness probes are initiated -// TimeoutSeconds - Number of seconds after which the probe times out -// PeriodSeconds - How often (in seconds) to perform the probe -type ProbeConfig struct { - LivenessPath string - ReadinessPath string - InitialDelaySeconds int32 - TimeoutSeconds int32 - PeriodSeconds int32 +func (p *ProbeConf) merge(overrides ProbeConf) { + // Override path if provided + if overrides.Path != "" { + p.Path = overrides.Path + } + // Override timing values if they are non-zero + if overrides.InitialDelaySeconds > 0 { + p.InitialDelaySeconds = overrides.InitialDelaySeconds + } + if overrides.TimeoutSeconds > 0 { + p.TimeoutSeconds = overrides.TimeoutSeconds + } + if overrides.PeriodSeconds > 0 { + p.PeriodSeconds = overrides.PeriodSeconds + } + if overrides.FailureThreshold > 0 { + p.FailureThreshold = overrides.FailureThreshold + } } -// SetProbes - configures and returns liveness and readiness probes based on the provided settings -func SetProbes(port int, disableNonTLSListeners bool, config ProbeConfig) (*v1.Probe, *v1.Probe, error) { +// CreateProbeSet - creates all probes at once using the interface +func CreateProbeSet( + port int32, + scheme *v1.URIScheme, + overrides ProbeOverrides, + defaults OverrideSpec, +) (*ProbeSet, error) { - if port < 1 || port > 65535 { - return nil, nil, fmt.Errorf("%w: %d", util.ErrInvalidPort, port) + livenessProbe, err := SetProbeConf( + port, + scheme, + func() ProbeConf { + if defaults.LivenessProbes == nil { + defaults.LivenessProbes = &ProbeConf{} + } + baseConf := *defaults.LivenessProbes + if p := overrides.GetLivenessProbes(); p != nil { + baseConf.merge(*p) + } + return baseConf + }(), + ) + + // Could not process probes config + if err != nil { + return nil, err } - var scheme v1.URIScheme - if disableNonTLSListeners { - scheme = v1.URISchemeHTTPS - } else { - scheme = v1.URISchemeHTTP + readinessProbe, err := SetProbeConf( + port, + scheme, + func() ProbeConf { + if defaults.ReadinessProbes == nil { + defaults.ReadinessProbes = &ProbeConf{} + } + baseConf := *defaults.ReadinessProbes + if p := overrides.GetReadinessProbes(); p != nil { + baseConf.merge(*p) + } + return baseConf + }(), + ) + + // Could not process probes config + if err != nil { + return nil, err } - livenessProbe := &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - HTTPGet: &v1.HTTPGetAction{ - Path: config.LivenessPath, - Port: intstr.FromInt(port), - Scheme: scheme, - }, - }, - InitialDelaySeconds: config.InitialDelaySeconds, - TimeoutSeconds: config.TimeoutSeconds, - PeriodSeconds: config.PeriodSeconds, + startupProbe, err := SetProbeConf( + port, + scheme, + func() ProbeConf { + if defaults.StartupProbes == nil { + defaults.StartupProbes = &ProbeConf{} + } + baseConf := *defaults.StartupProbes + if p := overrides.GetStartupProbes(); p != nil { + baseConf.merge(*p) + } + return baseConf + }(), + ) + + // Could not process probes config + if err != nil { + return nil, err } - readinessProbe := &v1.Probe{ + return &ProbeSet{ + Liveness: livenessProbe, + Readiness: readinessProbe, + Startup: startupProbe, + }, nil +} + +// SetProbeConf configures and returns liveness and readiness probes based on +// the provided settings +func SetProbeConf(port int32, scheme *v1.URIScheme, config ProbeConf) (*v1.Probe, error) { + if port < 1 || port > 65535 { + return nil, fmt.Errorf("%w: %d", util.ErrInvalidPort, port) + } + probe := &v1.Probe{ ProbeHandler: v1.ProbeHandler{ HTTPGet: &v1.HTTPGetAction{ - Path: config.ReadinessPath, - Port: intstr.FromInt(port), - Scheme: scheme, + Path: config.Path, + Port: intstr.FromInt32(port), }, }, InitialDelaySeconds: config.InitialDelaySeconds, TimeoutSeconds: config.TimeoutSeconds, PeriodSeconds: config.PeriodSeconds, + FailureThreshold: config.FailureThreshold, + } + if scheme != nil { + probe.HTTPGet.Scheme = *scheme + } + return probe, nil +} + +// ValidateProbeConf - This function can be used at webhooks level to explicitly +// validate the overrides +func ValidateProbeConf(basePath *field.Path, config *ProbeConf) field.ErrorList { + errorList := field.ErrorList{} + // nothing to validate, return an empty errorList + if config == nil { + return errorList + } + // Path validation: fail is explicitly set as an empty string + // or the endpoint does't start with "/" + if config.Path != "" && !strings.HasPrefix(config.Path, "/") { + err := field.Invalid(basePath.Child("path"), config.Path, + "path must start with '/' if specified") + errorList = append(errorList, err) + } + + // InitialDelaySeconds validation: must be > 0 + if config.InitialDelaySeconds < 0 { + err := field.Invalid(basePath.Child("initialDelaySeconds"), config.InitialDelaySeconds, + "initialDelaySeconds must be non-negative") + errorList = append(errorList, err) + } + + // TimeoutSeconds validation: fail if it's a negative number + if config.TimeoutSeconds != 0 && config.TimeoutSeconds < 1 { + err := field.Invalid(basePath.Child("timeoutSeconds"), config.TimeoutSeconds, + "timeoutSeconds must be at least 1 second when set") + errorList = append(errorList, err) + } + + // PeriodSeconds validation: fail if it's set as a negative number + if config.PeriodSeconds != 0 && config.PeriodSeconds < 1 { + err := field.Invalid(basePath.Child("periodSeconds"), config.PeriodSeconds, + "periodSeconds must be at least 1 second when set") + errorList = append(errorList, err) + } + + // FailureThreshold validation: fail if it's set as a negative number + if config.FailureThreshold != 0 && config.FailureThreshold < 1 { + err := field.Invalid(basePath.Child("failureThreshold"), config.FailureThreshold, + "failureThreshold must be at least 1 when set") + errorList = append(errorList, err) } - return livenessProbe, readinessProbe, nil + return errorList } diff --git a/modules/common/probes/probes_test.go b/modules/common/probes/probes_test.go index ccf41b97..37471455 100644 --- a/modules/common/probes/probes_test.go +++ b/modules/common/probes/probes_test.go @@ -22,57 +22,395 @@ import ( v1 "k8s.io/api/core/v1" ) -func TestSetProbes(t *testing.T) { +func TestSetProbeConf(t *testing.T) { tests := []struct { - name string - port int - disable bool - wantURI v1.URIScheme - wantErr bool + name string + port int32 + scheme *v1.URIScheme + config ProbeConf + wantURI v1.URIScheme + wantErr bool + wantPath string }{ { - name: "Disable NonTLS Listeners", - port: 8080, - disable: true, - wantURI: v1.URISchemeHTTPS, + name: "Valid port with HTTP scheme", + port: 8080, + scheme: &[]v1.URIScheme{v1.URISchemeHTTP}[0], + config: ProbeConf{ + Path: "/health", + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + FailureThreshold: 3, + }, + wantURI: v1.URISchemeHTTP, + wantPath: "/health", }, { - name: "Enable NonTLS Listeners", - port: 8080, - disable: false, - wantURI: v1.URISchemeHTTP, + name: "Valid port with HTTPS scheme", + port: 8443, + scheme: &[]v1.URIScheme{v1.URISchemeHTTPS}[0], + config: ProbeConf{ + Path: "/ready", + InitialDelaySeconds: 15, + TimeoutSeconds: 10, + PeriodSeconds: 5, + FailureThreshold: 1, + }, + wantURI: v1.URISchemeHTTPS, + wantPath: "/ready", + }, + { + name: "Valid port without scheme", + port: 9090, + scheme: nil, + config: ProbeConf{ + Path: "/status", + InitialDelaySeconds: 20, + TimeoutSeconds: 3, + PeriodSeconds: 15, + FailureThreshold: 5, + }, + wantPath: "/status", }, { name: "Negative Port", port: -8080, - disable: false, + scheme: nil, + config: ProbeConf{Path: "/health"}, wantErr: true, }, { name: "Port Larger than 65535", port: 70000, - disable: false, + scheme: nil, + config: ProbeConf{Path: "/health"}, + wantErr: true, + }, + { + name: "Port zero", + port: 0, + scheme: nil, + config: ProbeConf{Path: "/health"}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - liveness, _, err := SetProbes(tt.port, tt.disable, ProbeConfig{}) + probe, err := SetProbeConf(tt.port, tt.scheme, tt.config) if tt.wantErr { if err == nil { - t.Errorf("SetProbes() expected error but got none") + t.Errorf("SetProbeConf() expected error but got none") } return } else if err != nil { - t.Errorf("SetProbes() unexpected error: %v", err) + t.Errorf("SetProbeConf() unexpected error: %v", err) return } - // Only check the liveness probe if there was no error - if liveness.HTTPGet.Scheme != tt.wantURI { - t.Errorf("SetProbes() got = %v, want %v", liveness.HTTPGet.Scheme, tt.wantURI) + if probe.HTTPGet.Path != tt.wantPath { + t.Errorf("SetProbeConf() path = %v, want %v", probe.HTTPGet.Path, tt.wantPath) + } + if tt.scheme != nil && probe.HTTPGet.Scheme != tt.wantURI { + t.Errorf("SetProbeConf() scheme = %v, want %v", probe.HTTPGet.Scheme, tt.wantURI) + } + if probe.InitialDelaySeconds != tt.config.InitialDelaySeconds { + t.Errorf("SetProbeConf() initialDelaySeconds = %v, want %v", probe.InitialDelaySeconds, tt.config.InitialDelaySeconds) + } + if probe.TimeoutSeconds != tt.config.TimeoutSeconds { + t.Errorf("SetProbeConf() timeoutSeconds = %v, want %v", probe.TimeoutSeconds, tt.config.TimeoutSeconds) + } + if probe.PeriodSeconds != tt.config.PeriodSeconds { + t.Errorf("SetProbeConf() periodSeconds = %v, want %v", probe.PeriodSeconds, tt.config.PeriodSeconds) + } + if probe.FailureThreshold != tt.config.FailureThreshold { + t.Errorf("SetProbeConf() failureThreshold = %v, want %v", probe.FailureThreshold, tt.config.FailureThreshold) + } + }) + } +} + +func TestCreateProbeSet(t *testing.T) { + defaultLiveness := &ProbeConf{ + Path: "/health", + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + FailureThreshold: 3, + } + defaultReadiness := &ProbeConf{ + Path: "/ready", + InitialDelaySeconds: 15, + TimeoutSeconds: 3, + PeriodSeconds: 5, + FailureThreshold: 1, + } + defaultStartup := &ProbeConf{ + Path: "/startup", + InitialDelaySeconds: 10, + TimeoutSeconds: 10, + PeriodSeconds: 5, + FailureThreshold: 10, + } + + defaults := OverrideSpec{ + LivenessProbes: defaultLiveness, + ReadinessProbes: defaultReadiness, + StartupProbes: defaultStartup, + } + + tests := []struct { + name string + port int32 + scheme *v1.URIScheme + overrides ProbeOverrides + defaults OverrideSpec + wantErr bool + }{ + { + name: "Valid configuration with no overrides", + port: 8080, + scheme: &[]v1.URIScheme{v1.URISchemeHTTP}[0], + overrides: OverrideSpec{}, + defaults: defaults, + wantErr: false, + }, + { + name: "Valid configuration with overrides", + port: 8443, + scheme: &[]v1.URIScheme{v1.URISchemeHTTPS}[0], + overrides: OverrideSpec{ + LivenessProbes: &ProbeConf{ + Path: "/custom-health", + InitialDelaySeconds: 60, + TimeoutSeconds: 10, + PeriodSeconds: 20, + FailureThreshold: 5, + }, + }, + defaults: defaults, + wantErr: false, + }, + { + name: "Invalid port", + port: -1, + scheme: nil, + overrides: OverrideSpec{}, + defaults: defaults, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + probeSet, err := CreateProbeSet(tt.port, tt.scheme, tt.overrides, tt.defaults) + if tt.wantErr { + if err == nil { + t.Errorf("CreateProbeSet() expected error but got none") + } + return + } else if err != nil { + t.Errorf("CreateProbeSet() unexpected error: %v", err) + return + } + if probeSet == nil { + t.Errorf("CreateProbeSet() returned nil probe set") + return + } + if probeSet.Liveness == nil { + t.Errorf("CreateProbeSet() liveness probe is nil") + } + if probeSet.Readiness == nil { + t.Errorf("CreateProbeSet() readiness probe is nil") + } + + if probeSet.Startup == nil { + t.Errorf("CreateProbeSet() startup probe is nil") } }) } } + +func TestOverrideSpecMethods(t *testing.T) { + livenessProbe := &ProbeConf{Path: "/health"} + readinessProbe := &ProbeConf{Path: "/ready"} + startupProbe := &ProbeConf{Path: "/startup"} + + override := OverrideSpec{ + LivenessProbes: livenessProbe, + ReadinessProbes: readinessProbe, + StartupProbes: startupProbe, + } + if override.GetLivenessProbes() != livenessProbe { + t.Errorf("GetLivenessProbes() = %v, want %v", override.GetLivenessProbes(), livenessProbe) + } + if override.GetReadinessProbes() != readinessProbe { + t.Errorf("GetReadinessProbes() = %v, want %v", override.GetReadinessProbes(), readinessProbe) + } + if override.GetStartupProbes() != startupProbe { + t.Errorf("GetStartupProbes() = %v, want %v", override.GetStartupProbes(), startupProbe) + } + emptyOverride := OverrideSpec{} + if emptyOverride.GetLivenessProbes() != nil { + t.Errorf("GetLivenessProbes() on empty override = %v, want nil", emptyOverride.GetLivenessProbes()) + } + if emptyOverride.GetReadinessProbes() != nil { + t.Errorf("GetReadinessProbes() on empty override = %v, want nil", emptyOverride.GetReadinessProbes()) + } + if emptyOverride.GetStartupProbes() != nil { + t.Errorf("GetStartupProbes() on empty override = %v, want nil", emptyOverride.GetStartupProbes()) + } +} + +func TestCreateProbeSetWithActualOverrides(t *testing.T) { + defaultLiveness := &ProbeConf{ + Path: "/health", + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + FailureThreshold: 3, + } + defaultReadiness := &ProbeConf{ + Path: "/ready", + InitialDelaySeconds: 15, + TimeoutSeconds: 3, + PeriodSeconds: 5, + FailureThreshold: 1, + } + defaultStartup := &ProbeConf{ + Path: "/startup", + InitialDelaySeconds: 10, + TimeoutSeconds: 10, + PeriodSeconds: 5, + FailureThreshold: 10, + } + + defaults := OverrideSpec{ + LivenessProbes: defaultLiveness, + ReadinessProbes: defaultReadiness, + StartupProbes: defaultStartup, + } + + tests := []struct { + name string + overrides OverrideSpec + expectedLiveness ProbeConf + expectedReadiness ProbeConf + expectedStartup ProbeConf + }{ + { + name: "Override only liveness probe", + overrides: OverrideSpec{ + LivenessProbes: &ProbeConf{ + Path: "/custom-health", + InitialDelaySeconds: 60, + TimeoutSeconds: 10, + PeriodSeconds: 20, + FailureThreshold: 5, + }, + }, + expectedLiveness: ProbeConf{ + Path: "/custom-health", + InitialDelaySeconds: 60, + TimeoutSeconds: 10, + PeriodSeconds: 20, + FailureThreshold: 5, + }, + expectedReadiness: *defaultReadiness, + expectedStartup: *defaultStartup, + }, + { + name: "Override all probes", + overrides: OverrideSpec{ + LivenessProbes: &ProbeConf{ + Path: "/override-health", + InitialDelaySeconds: 45, + TimeoutSeconds: 8, + PeriodSeconds: 15, + FailureThreshold: 4, + }, + ReadinessProbes: &ProbeConf{ + Path: "/override-ready", + InitialDelaySeconds: 20, + TimeoutSeconds: 6, + PeriodSeconds: 8, + FailureThreshold: 2, + }, + StartupProbes: &ProbeConf{ + Path: "/override-startup", + InitialDelaySeconds: 25, + TimeoutSeconds: 12, + PeriodSeconds: 7, + FailureThreshold: 15, + }, + }, + expectedLiveness: ProbeConf{ + Path: "/override-health", + InitialDelaySeconds: 45, + TimeoutSeconds: 8, + PeriodSeconds: 15, + FailureThreshold: 4, + }, + expectedReadiness: ProbeConf{ + Path: "/override-ready", + InitialDelaySeconds: 20, + TimeoutSeconds: 6, + PeriodSeconds: 8, + FailureThreshold: 2, + }, + expectedStartup: ProbeConf{ + Path: "/override-startup", + InitialDelaySeconds: 25, + TimeoutSeconds: 12, + PeriodSeconds: 7, + FailureThreshold: 15, + }, + }, + { + name: "No overrides - use defaults", + overrides: OverrideSpec{}, + expectedLiveness: *defaultLiveness, + expectedReadiness: *defaultReadiness, + expectedStartup: *defaultStartup, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + probeSet, err := CreateProbeSet(8080, nil, tt.overrides, defaults) + if err != nil { + t.Fatalf("CreateProbeSet() unexpected error: %v", err) + } + // Validate liveness probe + validateProbe(t, "liveness", probeSet.Liveness, tt.expectedLiveness) + // Validate readiness probe + validateProbe(t, "readiness", probeSet.Readiness, tt.expectedReadiness) + // Validate startup probe + validateProbe(t, "startup", probeSet.Startup, tt.expectedStartup) + }) + } +} + +func validateProbe(t *testing.T, probeType string, actual *v1.Probe, expected ProbeConf) { + t.Helper() + if actual == nil { + t.Errorf("%s probe is nil", probeType) + return + } + if actual.HTTPGet.Path != expected.Path { + t.Errorf("%s probe path = %q, want %q", probeType, actual.HTTPGet.Path, expected.Path) + } + if actual.InitialDelaySeconds != expected.InitialDelaySeconds { + t.Errorf("%s probe initialDelaySeconds = %d, want %d", probeType, actual.InitialDelaySeconds, expected.InitialDelaySeconds) + } + if actual.TimeoutSeconds != expected.TimeoutSeconds { + t.Errorf("%s probe timeoutSeconds = %d, want %d", probeType, actual.TimeoutSeconds, expected.TimeoutSeconds) + } + if actual.PeriodSeconds != expected.PeriodSeconds { + t.Errorf("%s probe periodSeconds = %d, want %d", probeType, actual.PeriodSeconds, expected.PeriodSeconds) + } + if actual.FailureThreshold != expected.FailureThreshold { + t.Errorf("%s probe failureThreshold = %d, want %d", probeType, actual.FailureThreshold, expected.FailureThreshold) + } +} diff --git a/modules/common/probes/types.go b/modules/common/probes/types.go new file mode 100644 index 00000000..dd474439 --- /dev/null +++ b/modules/common/probes/types.go @@ -0,0 +1,107 @@ +/* +Copyright 2026 Red Hat + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// +kubebuilder:object:generate:=true + +// Package probes provides utilities for configuring Kubernetes liveness and +// readiness probes +package probes + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +// ProbeConf - the configuration for liveness and readiness probes +// LivenessPath - Endpoint path for the liveness probe +// ReadinessPath - Endpoint path for the readiness probe +// InitialDelaySeconds - Number of seconds after the container starts before liveness/readiness probes are initiated +// TimeoutSeconds - Number of seconds after which the probe times out +// PeriodSeconds - How often (in seconds) to perform the probe +type ProbeConf struct { + // +kubebuilder:validation:Pattern=`^(/.*)?$` + Path string `json:"path,omitempty"` + // +kubebuilder:validation:Minimum=0 + InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"` + // +kubebuilder:validation:Minimum=1 + TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"` + // +kubebuilder:validation:Minimum=1 + PeriodSeconds int32 `json:"periodSeconds,omitempty"` + // +kubebuilder:validation:Minimum=1 + FailureThreshold int32 `json:"failureThreshold,omitempty"` +} + +// OverrideSpec to override StatefulSet fields +type OverrideSpec struct { + // Override configuration for the StatefulSet like Probes and other tunable + // fields + LivenessProbes *ProbeConf `json:"livenessProbes,omitempty"` + ReadinessProbes *ProbeConf `json:"readinessProbes,omitempty"` + StartupProbes *ProbeConf `json:"startupProbes,omitempty"` +} + +// ProbeSet holds all the probes for a service +type ProbeSet struct { + Liveness *v1.Probe + Readiness *v1.Probe + Startup *v1.Probe +} + +// ProbeOverrides interface that all override specs can implement +// +kubebuilder:object:generate:=false +type ProbeOverrides interface { + GetLivenessProbes() *ProbeConf + GetReadinessProbes() *ProbeConf + GetStartupProbes() *ProbeConf + ValidateProbes(basePath *field.Path) field.ErrorList +} + +// GetLivenessProbes - +func (o OverrideSpec) GetLivenessProbes() *ProbeConf { + return o.LivenessProbes +} + +// GetReadinessProbes - +func (o OverrideSpec) GetReadinessProbes() *ProbeConf { + return o.ReadinessProbes +} + +// GetStartupProbes - +func (o OverrideSpec) GetStartupProbes() *ProbeConf { + return o.StartupProbes +} + +// ValidateProbes represents the entrypoint for webhook validation. It processes +// the ProbeSet (liveness, readiness and startup probes) and performs a validation +// over the overrides passed as input +func (o OverrideSpec) ValidateProbes(basePath *field.Path) field.ErrorList { + errorList := field.ErrorList{} + + if o.GetLivenessProbes() != nil { + errorList = append(errorList, + ValidateProbeConf(basePath.Child("livenessProbe"), o.GetLivenessProbes())...) + } + + if o.GetReadinessProbes() != nil { + errorList = append(errorList, + ValidateProbeConf(basePath.Child("readinessProbe"), o.GetReadinessProbes())...) + } + + if o.GetStartupProbes() != nil { + errorList = append(errorList, + ValidateProbeConf(basePath.Child("startupProbe"), o.GetStartupProbes())...) + } + return errorList +} diff --git a/modules/common/probes/zz_generated.deepcopy.go b/modules/common/probes/zz_generated.deepcopy.go new file mode 100644 index 00000000..f3f3cf0a --- /dev/null +++ b/modules/common/probes/zz_generated.deepcopy.go @@ -0,0 +1,100 @@ +//go:build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package probes + +import ( + "k8s.io/api/core/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverrideSpec) DeepCopyInto(out *OverrideSpec) { + *out = *in + if in.LivenessProbes != nil { + in, out := &in.LivenessProbes, &out.LivenessProbes + *out = new(ProbeConf) + **out = **in + } + if in.ReadinessProbes != nil { + in, out := &in.ReadinessProbes, &out.ReadinessProbes + *out = new(ProbeConf) + **out = **in + } + if in.StartupProbes != nil { + in, out := &in.StartupProbes, &out.StartupProbes + *out = new(ProbeConf) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverrideSpec. +func (in *OverrideSpec) DeepCopy() *OverrideSpec { + if in == nil { + return nil + } + out := new(OverrideSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProbeConf) DeepCopyInto(out *ProbeConf) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProbeConf. +func (in *ProbeConf) DeepCopy() *ProbeConf { + if in == nil { + return nil + } + out := new(ProbeConf) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProbeSet) DeepCopyInto(out *ProbeSet) { + *out = *in + if in.Liveness != nil { + in, out := &in.Liveness, &out.Liveness + *out = new(v1.Probe) + (*in).DeepCopyInto(*out) + } + if in.Readiness != nil { + in, out := &in.Readiness, &out.Readiness + *out = new(v1.Probe) + (*in).DeepCopyInto(*out) + } + if in.Startup != nil { + in, out := &in.Startup, &out.Startup + *out = new(v1.Probe) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProbeSet. +func (in *ProbeSet) DeepCopy() *ProbeSet { + if in == nil { + return nil + } + out := new(ProbeSet) + in.DeepCopyInto(out) + return out +}