@@ -30,12 +30,23 @@ import (
3030 "strings"
3131)
3232
33- func (p * ProbeConf ) merge (overrides ProbeConf ) {
34- // Override path if provided
33+ // Merge applies non-zero override values onto the receiver
34+ func (p * ProbeConf ) Merge (overrides ProbeConf ) {
35+ if overrides .Type != "" {
36+ p .Type = overrides .Type
37+ }
3538 if overrides .Path != "" {
3639 p .Path = overrides .Path
3740 }
38- // Override timing values if they are non-zero
41+ if len (overrides .Command ) > 0 {
42+ p .Command = overrides .Command
43+ }
44+ if overrides .Port > 0 {
45+ p .Port = overrides .Port
46+ }
47+ if overrides .Scheme != nil {
48+ p .Scheme = overrides .Scheme
49+ }
3950 if overrides .InitialDelaySeconds > 0 {
4051 p .InitialDelaySeconds = overrides .InitialDelaySeconds
4152 }
@@ -50,70 +61,61 @@ func (p *ProbeConf) merge(overrides ProbeConf) {
5061 }
5162}
5263
53- // CreateProbeSet - creates all probes at once using the interface
64+ // CreateProbeSet creates all probes at once using the interface.
65+ // Port and scheme are applied to all probes as HTTP GET handler parameters.
66+ // For mixed probe types (e.g. HTTP and exec), use CreateProbeSetV2 instead
67+ // with Port/Scheme set in the individual ProbeConf defaults.
5468func CreateProbeSet (
5569 port int32 ,
5670 scheme * v1.URIScheme ,
5771 overrides ProbeOverrides ,
5872 defaults OverrideSpec ,
5973) (* ProbeSet , error ) {
74+ for _ , p := range []* ProbeConf {defaults .LivenessProbes , defaults .ReadinessProbes , defaults .StartupProbes } {
75+ if p != nil {
76+ p .Port = port
77+ p .Scheme = scheme
78+ }
79+ }
80+ return CreateProbeSetV2 (overrides , defaults )
81+ }
6082
61- livenessProbe , err := SetProbeConf (
62- port ,
63- scheme ,
64- func () ProbeConf {
65- if defaults .LivenessProbes == nil {
66- defaults .LivenessProbes = & ProbeConf {}
67- }
68- baseConf := * defaults .LivenessProbes
69- if p := overrides .GetLivenessProbes (); p != nil {
70- baseConf .merge (* p )
71- }
72- return baseConf
73- }(),
74- )
83+ // CreateProbeSetV2 creates all probes at once using the interface.
84+ // Each probe's handler type, port, scheme, path, and command are determined
85+ // by the ProbeConf fields in the defaults and overrides.
86+ func CreateProbeSetV2 (
87+ overrides ProbeOverrides ,
88+ defaults OverrideSpec ,
89+ ) (* ProbeSet , error ) {
7590
76- // Could not process probes config
91+ mergeConf := func (base * ProbeConf , override * ProbeConf ) ProbeConf {
92+ if base == nil {
93+ base = & ProbeConf {}
94+ }
95+ conf := * base
96+ if override != nil {
97+ conf .Merge (* override )
98+ }
99+ return conf
100+ }
101+
102+ livenessProbe , err := SetProbeConfV2 (
103+ mergeConf (defaults .LivenessProbes , overrides .GetLivenessProbes ()),
104+ )
77105 if err != nil {
78106 return nil , err
79107 }
80108
81- readinessProbe , err := SetProbeConf (
82- port ,
83- scheme ,
84- func () ProbeConf {
85- if defaults .ReadinessProbes == nil {
86- defaults .ReadinessProbes = & ProbeConf {}
87- }
88- baseConf := * defaults .ReadinessProbes
89- if p := overrides .GetReadinessProbes (); p != nil {
90- baseConf .merge (* p )
91- }
92- return baseConf
93- }(),
109+ readinessProbe , err := SetProbeConfV2 (
110+ mergeConf (defaults .ReadinessProbes , overrides .GetReadinessProbes ()),
94111 )
95-
96- // Could not process probes config
97112 if err != nil {
98113 return nil , err
99114 }
100115
101- startupProbe , err := SetProbeConf (
102- port ,
103- scheme ,
104- func () ProbeConf {
105- if defaults .StartupProbes == nil {
106- defaults .StartupProbes = & ProbeConf {}
107- }
108- baseConf := * defaults .StartupProbes
109- if p := overrides .GetStartupProbes (); p != nil {
110- baseConf .merge (* p )
111- }
112- return baseConf
113- }(),
116+ startupProbe , err := SetProbeConfV2 (
117+ mergeConf (defaults .StartupProbes , overrides .GetStartupProbes ()),
114118 )
115-
116- // Could not process probes config
117119 if err != nil {
118120 return nil , err
119121 }
@@ -125,72 +127,88 @@ func CreateProbeSet(
125127 }, nil
126128}
127129
128- // SetProbeConf configures and returns liveness and readiness probes based on
129- // the provided settings
130- func SetProbeConf ( port int32 , scheme * v1. URIScheme , config ProbeConf ) ( * v1. Probe , error ) {
131- if port < 1 || port > 65535 {
132- return nil , fmt . Errorf ( "%w: %d" , util . ErrInvalidPort , port )
133- }
130+ // SetProbeConfV2 configures and returns a probe based on the ProbeConf
131+ // settings. The probe handler type is determined by ProbeConf.Type:
132+ // ProbeHandlerExec creates an exec probe using ProbeConf.Command, while
133+ // ProbeHandlerHTTP (or unset) creates an HTTP GET probe using ProbeConf.Port,
134+ // ProbeConf.Path, and ProbeConf.Scheme.
135+ func SetProbeConfV2 ( config ProbeConf ) ( * v1. Probe , error ) {
134136 probe := & v1.Probe {
135- ProbeHandler : v1.ProbeHandler {
136- HTTPGet : & v1.HTTPGetAction {
137- Path : config .Path ,
138- Port : intstr .FromInt32 (port ),
139- },
140- },
141137 InitialDelaySeconds : config .InitialDelaySeconds ,
142138 TimeoutSeconds : config .TimeoutSeconds ,
143139 PeriodSeconds : config .PeriodSeconds ,
144140 FailureThreshold : config .FailureThreshold ,
145141 }
146- if scheme != nil {
147- probe .HTTPGet .Scheme = * scheme
142+
143+ switch config .Type {
144+ case ProbeHandlerExec :
145+ if len (config .Command ) == 0 {
146+ return nil , util .ErrExecProbeCommandRequired
147+ }
148+ probe .ProbeHandler = v1.ProbeHandler {
149+ Exec : & v1.ExecAction {
150+ Command : config .Command ,
151+ },
152+ }
153+ default :
154+ if config .Port < 1 || config .Port > 65535 {
155+ return nil , fmt .Errorf ("%w: %d" , util .ErrInvalidPort , config .Port )
156+ }
157+ probe .ProbeHandler = v1.ProbeHandler {
158+ HTTPGet : & v1.HTTPGetAction {
159+ Path : config .Path ,
160+ Port : intstr .FromInt32 (config .Port ),
161+ },
162+ }
163+ if config .Scheme != nil {
164+ probe .HTTPGet .Scheme = * config .Scheme
165+ }
148166 }
149167 return probe , nil
150168}
151169
152- // ValidateProbeConf - This function can be used at webhooks level to explicitly
153- // validate the overrides
170+ // ValidateProbeConf validates probe configuration overrides for use at the
171+ // webhook level
154172func ValidateProbeConf (basePath * field.Path , config * ProbeConf ) field.ErrorList {
155173 errorList := field.ErrorList {}
156- // nothing to validate, return an empty errorList
157174 if config == nil {
158175 return errorList
159176 }
160- // Path validation: fail is explicitly set as an empty string
161- // or the endpoint does't start with "/"
162- if config .Path != "" && ! strings .HasPrefix (config .Path , "/" ) {
163- err := field .Invalid (basePath .Child ("path" ), config .Path ,
164- "path must start with '/' if specified" )
165- errorList = append (errorList , err )
177+
178+ switch config .Type {
179+ case ProbeHandlerExec :
180+ if len (config .Command ) == 0 {
181+ errorList = append (errorList , field .Required (basePath .Child ("command" ),
182+ "command is required for exec probe type" ))
183+ }
184+ case "" , ProbeHandlerHTTP :
185+ if config .Path != "" && ! strings .HasPrefix (config .Path , "/" ) {
186+ errorList = append (errorList , field .Invalid (basePath .Child ("path" ), config .Path ,
187+ "path must start with '/' if specified" ))
188+ }
189+ default :
190+ errorList = append (errorList , field .Invalid (basePath .Child ("type" ), config .Type ,
191+ "type must be one of: HTTP, Exec, or unset" ))
166192 }
167193
168- // InitialDelaySeconds validation: must be > 0
169194 if config .InitialDelaySeconds < 0 {
170- err := field .Invalid (basePath .Child ("initialDelaySeconds" ), config .InitialDelaySeconds ,
171- "initialDelaySeconds must be non-negative" )
172- errorList = append (errorList , err )
195+ errorList = append (errorList , field .Invalid (basePath .Child ("initialDelaySeconds" ), config .InitialDelaySeconds ,
196+ "initialDelaySeconds must be non-negative" ))
173197 }
174198
175- // TimeoutSeconds validation: fail if it's a negative number
176199 if config .TimeoutSeconds != 0 && config .TimeoutSeconds < 1 {
177- err := field .Invalid (basePath .Child ("timeoutSeconds" ), config .TimeoutSeconds ,
178- "timeoutSeconds must be at least 1 second when set" )
179- errorList = append (errorList , err )
200+ errorList = append (errorList , field .Invalid (basePath .Child ("timeoutSeconds" ), config .TimeoutSeconds ,
201+ "timeoutSeconds must be at least 1 second when set" ))
180202 }
181203
182- // PeriodSeconds validation: fail if it's set as a negative number
183204 if config .PeriodSeconds != 0 && config .PeriodSeconds < 1 {
184- err := field .Invalid (basePath .Child ("periodSeconds" ), config .PeriodSeconds ,
185- "periodSeconds must be at least 1 second when set" )
186- errorList = append (errorList , err )
205+ errorList = append (errorList , field .Invalid (basePath .Child ("periodSeconds" ), config .PeriodSeconds ,
206+ "periodSeconds must be at least 1 second when set" ))
187207 }
188208
189- // FailureThreshold validation: fail if it's set as a negative number
190209 if config .FailureThreshold != 0 && config .FailureThreshold < 1 {
191- err := field .Invalid (basePath .Child ("failureThreshold" ), config .FailureThreshold ,
192- "failureThreshold must be at least 1 when set" )
193- errorList = append (errorList , err )
210+ errorList = append (errorList , field .Invalid (basePath .Child ("failureThreshold" ), config .FailureThreshold ,
211+ "failureThreshold must be at least 1 when set" ))
194212 }
195213
196214 return errorList
0 commit comments