@@ -24,12 +24,14 @@ import (
24
24
apiequality "k8s.io/apimachinery/pkg/api/equality"
25
25
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
26
26
"k8s.io/apimachinery/pkg/util/sets"
27
+ utilvalidation "k8s.io/apimachinery/pkg/util/validation"
27
28
validationutil "k8s.io/apimachinery/pkg/util/validation"
28
29
"k8s.io/apimachinery/pkg/util/validation/field"
29
30
utilfeature "k8s.io/apiserver/pkg/util/feature"
30
31
"k8s.io/apiserver/pkg/util/webhook"
31
32
32
33
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
34
+ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
33
35
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
34
36
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
35
37
)
@@ -113,6 +115,10 @@ func ValidateCustomResourceDefinitionVersion(version *apiextensions.CustomResour
113
115
114
116
// ValidateCustomResourceDefinitionSpec statically validates
115
117
func ValidateCustomResourceDefinitionSpec (spec * apiextensions.CustomResourceDefinitionSpec , fldPath * field.Path ) field.ErrorList {
118
+ return validateCustomResourceDefinitionSpec (spec , true , fldPath )
119
+ }
120
+
121
+ func validateCustomResourceDefinitionSpec (spec * apiextensions.CustomResourceDefinitionSpec , requireRecognizedVersion bool , fldPath * field.Path ) field.ErrorList {
116
122
allErrs := field.ErrorList {}
117
123
118
124
if len (spec .Group ) == 0 {
@@ -205,7 +211,7 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
205
211
}
206
212
}
207
213
208
- allErrs = append (allErrs , ValidateCustomResourceConversion (spec .Conversion , fldPath .Child ("conversion" ))... )
214
+ allErrs = append (allErrs , validateCustomResourceConversion (spec .Conversion , requireRecognizedVersion , fldPath .Child ("conversion" ))... )
209
215
210
216
return allErrs
211
217
}
@@ -225,8 +231,66 @@ func validateEnumStrings(fldPath *field.Path, value string, accepted []string, r
225
231
return field.ErrorList {field .NotSupported (fldPath , value , accepted )}
226
232
}
227
233
234
+ var acceptedConversionReviewVersion = []string {v1beta1 .SchemeGroupVersion .Version }
235
+
236
+ func isAcceptedConversionReviewVersion (v string ) bool {
237
+ for _ , version := range acceptedConversionReviewVersion {
238
+ if v == version {
239
+ return true
240
+ }
241
+ }
242
+ return false
243
+ }
244
+
245
+ func validateConversionReviewVersions (versions []string , requireRecognizedVersion bool , fldPath * field.Path ) field.ErrorList {
246
+ allErrs := field.ErrorList {}
247
+ if len (versions ) < 1 {
248
+ allErrs = append (allErrs , field .Required (fldPath , "" ))
249
+ } else {
250
+ seen := map [string ]bool {}
251
+ hasAcceptedVersion := false
252
+ for i , v := range versions {
253
+ if seen [v ] {
254
+ allErrs = append (allErrs , field .Invalid (fldPath .Index (i ), v , "duplicate version" ))
255
+ continue
256
+ }
257
+ seen [v ] = true
258
+ for _ , errString := range utilvalidation .IsDNS1035Label (v ) {
259
+ allErrs = append (allErrs , field .Invalid (fldPath .Index (i ), v , errString ))
260
+ }
261
+ if isAcceptedConversionReviewVersion (v ) {
262
+ hasAcceptedVersion = true
263
+ }
264
+ }
265
+ if requireRecognizedVersion && ! hasAcceptedVersion {
266
+ allErrs = append (allErrs , field .Invalid (
267
+ fldPath , versions ,
268
+ fmt .Sprintf ("none of the versions accepted by this server. accepted version(s) are %v" ,
269
+ strings .Join (acceptedConversionReviewVersion , ", " ))))
270
+ }
271
+ }
272
+ return allErrs
273
+ }
274
+
275
+ // hasValidConversionReviewVersion return true if there is a valid version or if the list is empty.
276
+ func hasValidConversionReviewVersionOrEmpty (versions []string ) bool {
277
+ if len (versions ) < 1 {
278
+ return true
279
+ }
280
+ for _ , v := range versions {
281
+ if isAcceptedConversionReviewVersion (v ) {
282
+ return true
283
+ }
284
+ }
285
+ return false
286
+ }
287
+
228
288
// ValidateCustomResourceConversion statically validates
229
289
func ValidateCustomResourceConversion (conversion * apiextensions.CustomResourceConversion , fldPath * field.Path ) field.ErrorList {
290
+ return validateCustomResourceConversion (conversion , true , fldPath )
291
+ }
292
+
293
+ func validateCustomResourceConversion (conversion * apiextensions.CustomResourceConversion , requireRecognizedVersion bool , fldPath * field.Path ) field.ErrorList {
230
294
allErrs := field.ErrorList {}
231
295
if conversion == nil {
232
296
return allErrs
@@ -250,15 +314,22 @@ func ValidateCustomResourceConversion(conversion *apiextensions.CustomResourceCo
250
314
allErrs = append (allErrs , webhook .ValidateWebhookService (fldPath .Child ("webhookClientConfig" ).Child ("service" ), cc .Service .Name , cc .Service .Namespace , cc .Service .Path )... )
251
315
}
252
316
}
253
- } else if conversion .WebhookClientConfig != nil {
254
- allErrs = append (allErrs , field .Forbidden (fldPath .Child ("webhookClientConfig" ), "should not be set when strategy is not set to Webhook" ))
317
+ allErrs = append (allErrs , validateConversionReviewVersions (conversion .ConversionReviewVersions , requireRecognizedVersion , fldPath .Child ("conversionReviewVersions" ))... )
318
+ } else {
319
+ if conversion .WebhookClientConfig != nil {
320
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("webhookClientConfig" ), "should not be set when strategy is not set to Webhook" ))
321
+ }
322
+ if len (conversion .ConversionReviewVersions ) > 0 {
323
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("conversionReviewVersions" ), "should not be set when strategy is not set to Webhook" ))
324
+ }
255
325
}
256
326
return allErrs
257
327
}
258
328
259
329
// ValidateCustomResourceDefinitionSpecUpdate statically validates
260
330
func ValidateCustomResourceDefinitionSpecUpdate (spec , oldSpec * apiextensions.CustomResourceDefinitionSpec , established bool , fldPath * field.Path ) field.ErrorList {
261
- allErrs := ValidateCustomResourceDefinitionSpec (spec , fldPath )
331
+ requireRecognizedVersion := oldSpec .Conversion == nil || hasValidConversionReviewVersionOrEmpty (oldSpec .Conversion .ConversionReviewVersions )
332
+ allErrs := validateCustomResourceDefinitionSpec (spec , requireRecognizedVersion , fldPath )
262
333
263
334
if established {
264
335
// these effect the storage and cannot be changed therefore
0 commit comments