Skip to content

Commit f9afe46

Browse files
authored
Merge pull request kubernetes#78829 from sttts/sttts-crd-embedded-resource-metadata-defaulting
apiextensions: complete default-under-metadata validation and storage pruning
2 parents d2e2337 + 4fd200c commit f9afe46

File tree

19 files changed

+2337
-175
lines changed

19 files changed

+2337
-175
lines changed

staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/BUILD

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,17 @@ go_library(
1616
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
1717
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
1818
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema:go_default_library",
19-
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta:go_default_library",
20-
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/pruning:go_default_library",
19+
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting:go_default_library",
2120
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:go_default_library",
2221
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
2322
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
2423
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
25-
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
2624
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
2725
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
2826
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
2927
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
3028
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
3129
"//staging/src/k8s.io/apiserver/pkg/util/webhook:go_default_library",
32-
"//vendor/github.com/go-openapi/strfmt:go_default_library",
33-
"//vendor/github.com/go-openapi/validate:go_default_library",
3430
],
3531
)
3632

staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,10 @@ import (
2121
"reflect"
2222
"strings"
2323

24-
"github.com/go-openapi/strfmt"
25-
govalidate "github.com/go-openapi/validate"
26-
schemaobjectmeta "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta"
27-
2824
"k8s.io/apiextensions-apiserver/pkg/apihelpers"
25+
structuraldefaulting "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting"
2926
apiequality "k8s.io/apimachinery/pkg/api/equality"
3027
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
31-
"k8s.io/apimachinery/pkg/runtime"
3228
"k8s.io/apimachinery/pkg/runtime/schema"
3329
"k8s.io/apimachinery/pkg/util/sets"
3430
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
@@ -39,7 +35,6 @@ import (
3935
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
4036
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
4137
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
42-
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/pruning"
4338
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
4439
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
4540
)
@@ -659,6 +654,7 @@ func validateCustomResourceDefinitionValidation(customResourceValidation *apiext
659654
allowDefaults: opts.allowDefaults,
660655
requireValidPropertyType: opts.requireValidPropertyType,
661656
}
657+
662658
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(schema, fldPath.Child("openAPIV3Schema"), openAPIV3Schema, true)...)
663659

664660
if opts.requireStructuralSchema {
@@ -667,8 +663,13 @@ func validateCustomResourceDefinitionValidation(customResourceValidation *apiext
667663
if len(allErrs) == 0 {
668664
allErrs = append(allErrs, field.Invalid(fldPath.Child("openAPIV3Schema"), "", err.Error()))
669665
}
666+
} else if validationErrors := structuralschema.ValidateStructural(fldPath.Child("openAPIV3Schema"), ss); len(validationErrors) > 0 {
667+
allErrs = append(allErrs, validationErrors...)
668+
} else if validationErrors, err := structuraldefaulting.ValidateDefaults(fldPath.Child("openAPIV3Schema"), ss, true); err != nil {
669+
// this should never happen
670+
allErrs = append(allErrs, field.Invalid(fldPath.Child("openAPIV3Schema"), "", err.Error()))
670671
} else {
671-
allErrs = append(allErrs, structuralschema.ValidateStructural(ss, fldPath.Child("openAPIV3Schema"))...)
672+
allErrs = append(allErrs, validationErrors...)
672673
}
673674
}
674675
}
@@ -682,7 +683,7 @@ func validateCustomResourceDefinitionValidation(customResourceValidation *apiext
682683
return allErrs
683684
}
684685

685-
var metaFields = sets.NewString("metadata", "apiVersion", "kind")
686+
var metaFields = sets.NewString("metadata", "kind", "apiVersion")
686687

687688
// ValidateCustomResourceDefinitionOpenAPISchema statically validates
688689
func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSchemaProps, fldPath *field.Path, ssv specStandardValidator, isRoot bool) field.ErrorList {
@@ -726,6 +727,7 @@ func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSch
726727
if len(schema.Properties) != 0 {
727728
for property, jsonSchema := range schema.Properties {
728729
subSsv := ssv
730+
729731
if (isRoot || schema.XEmbeddedResource) && metaFields.Has(property) {
730732
// we recurse into the schema that applies to ObjectMeta.
731733
subSsv = ssv.withInsideResourceMeta()
@@ -825,43 +827,12 @@ func (v *specStandardValidatorV3) validate(schema *apiextensions.JSONSchemaProps
825827
allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), schema.Type, openapiV3Types.List()))
826828
}
827829

828-
if schema.Default != nil {
829-
if v.allowDefaults {
830-
if s, err := structuralschema.NewStructural(schema); err == nil {
831-
// ignore errors here locally. They will show up for the root of the schema.
832-
833-
clone := runtime.DeepCopyJSONValue(interface{}(*schema.Default))
834-
if !v.isInsideResourceMeta {
835-
// If we are under metadata, there are implicitly specified fields like kind, apiVersion, metadata, labels.
836-
// We cannot prune as they are pruned as well. This allows more defaults than we would like to.
837-
// TODO: be precise about pruning under metadata
838-
pruning.Prune(clone, s, s.XEmbeddedResource)
839-
840-
// TODO: coerce correctly if we are not at the object root, but somewhere below.
841-
if err := schemaobjectmeta.Coerce(fldPath, clone, s, s.XEmbeddedResource, false); err != nil {
842-
allErrs = append(allErrs, err)
843-
}
844-
845-
if !reflect.DeepEqual(clone, interface{}(*schema.Default)) {
846-
allErrs = append(allErrs, field.Invalid(fldPath.Child("default"), schema.Default, "must not have unknown fields"))
847-
} else if s.XEmbeddedResource {
848-
// validate an embedded resource
849-
schemaobjectmeta.Validate(fldPath, interface{}(*schema.Default), nil, true)
850-
}
851-
}
852-
853-
// validate the default value with user the provided schema.
854-
validator := govalidate.NewSchemaValidator(s.ToGoOpenAPI(), nil, "", strfmt.Default)
855-
856-
allErrs = append(allErrs, apiservervalidation.ValidateCustomResource(fldPath.Child("default"), interface{}(*schema.Default), validator)...)
857-
}
858-
} else {
859-
detail := "must not be set"
860-
if len(v.disallowDefaultsReason) > 0 {
861-
detail += " " + v.disallowDefaultsReason
862-
}
863-
allErrs = append(allErrs, field.Forbidden(fldPath.Child("default"), detail))
830+
if schema.Default != nil && !v.allowDefaults {
831+
detail := "must not be set"
832+
if len(v.disallowDefaultsReason) > 0 {
833+
detail += " " + v.disallowDefaultsReason
864834
}
835+
allErrs = append(allErrs, field.Forbidden(fldPath.Child("default"), detail))
865836
}
866837

867838
if schema.ID != "" {
@@ -1212,7 +1183,7 @@ func schemaIsNonStructural(schema *apiextensions.JSONSchemaProps) bool {
12121183
if err != nil {
12131184
return true
12141185
}
1215-
return len(structuralschema.ValidateStructural(ss, nil)) > 0
1186+
return len(structuralschema.ValidateStructural(nil, ss)) > 0
12161187
}
12171188

12181189
// requireValidPropertyType returns true if valid openapi v3 types should be required for the given API version

0 commit comments

Comments
 (0)