cleanup: check unstructured for Validate(Update) before validating

logic is the same. sets us up for another refactor
This commit is contained in:
Alexander Zielenski 2023-10-18 14:58:26 -07:00
parent 3a3dc870a2
commit cc0264f7fc
2 changed files with 35 additions and 57 deletions

View File

@ -18,6 +18,7 @@ package customresource
import ( import (
"context" "context"
"fmt"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
@ -163,25 +164,28 @@ func copyNonMetadata(original map[string]interface{}) map[string]interface{} {
// Validate validates a new CustomResource. // Validate validates a new CustomResource.
func (a customResourceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { func (a customResourceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
u, ok := obj.(*unstructured.Unstructured)
if !ok {
return field.ErrorList{field.Invalid(field.NewPath(""), u, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", u))}
}
var errs field.ErrorList var errs field.ErrorList
errs = append(errs, a.validator.Validate(ctx, obj, a.scale)...) errs = append(errs, a.validator.Validate(ctx, u, a.scale)...)
// validate embedded resources // validate embedded resources
if u, ok := obj.(*unstructured.Unstructured); ok { v := obj.GetObjectKind().GroupVersionKind().Version
v := obj.GetObjectKind().GroupVersionKind().Version errs = append(errs, schemaobjectmeta.Validate(nil, u.Object, a.structuralSchemas[v], false)...)
errs = append(errs, schemaobjectmeta.Validate(nil, u.Object, a.structuralSchemas[v], false)...)
// validate x-kubernetes-list-type "map" and "set" invariant // validate x-kubernetes-list-type "map" and "set" invariant
errs = append(errs, structurallisttype.ValidateListSetsAndMaps(nil, a.structuralSchemas[v], u.Object)...) errs = append(errs, structurallisttype.ValidateListSetsAndMaps(nil, a.structuralSchemas[v], u.Object)...)
// validate x-kubernetes-validations rules // validate x-kubernetes-validations rules
if celValidator, ok := a.celValidators[v]; ok { if celValidator, ok := a.celValidators[v]; ok {
if has, err := hasBlockingErr(errs); has { if has, err := hasBlockingErr(errs); has {
errs = append(errs, err) errs = append(errs, err)
} else { } else {
err, _ := celValidator.Validate(ctx, nil, a.structuralSchemas[v], u.Object, nil, celconfig.RuntimeCELCostBudget) err, _ := celValidator.Validate(ctx, nil, a.structuralSchemas[v], u.Object, nil, celconfig.RuntimeCELCostBudget)
errs = append(errs, err...) errs = append(errs, err...)
}
} }
} }
@ -234,18 +238,18 @@ func (customResourceStrategy) AllowUnconditionalUpdate() bool {
// ValidateUpdate is the default update validation for an end user updating status. // ValidateUpdate is the default update validation for an end user updating status.
func (a customResourceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { func (a customResourceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
var errs field.ErrorList
errs = append(errs, a.validator.ValidateUpdate(ctx, obj, old, a.scale)...)
uNew, ok := obj.(*unstructured.Unstructured) uNew, ok := obj.(*unstructured.Unstructured)
if !ok { if !ok {
return errs return field.ErrorList{field.Invalid(field.NewPath(""), obj, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", obj))}
} }
uOld, ok := old.(*unstructured.Unstructured) uOld, ok := old.(*unstructured.Unstructured)
if !ok { if !ok {
return errs return field.ErrorList{field.Invalid(field.NewPath(""), old, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", old))}
} }
var errs field.ErrorList
errs = append(errs, a.validator.ValidateUpdate(ctx, uNew, uOld, a.scale)...)
// Checks the embedded objects. We don't make a difference between update and create for those. // Checks the embedded objects. We don't make a difference between update and create for those.
v := obj.GetObjectKind().GroupVersionKind().Version v := obj.GetObjectKind().GroupVersionKind().Version
errs = append(errs, schemaobjectmeta.Validate(nil, uNew.Object, a.structuralSchemas[v], false)...) errs = append(errs, schemaobjectmeta.Validate(nil, uNew.Object, a.structuralSchemas[v], false)...)

View File

@ -44,58 +44,32 @@ type customResourceValidator struct {
statusSchemaValidator apiextensionsvalidation.SchemaValidator statusSchemaValidator apiextensionsvalidation.SchemaValidator
} }
func (a customResourceValidator) Validate(ctx context.Context, obj runtime.Object, scale *apiextensions.CustomResourceSubresourceScale) field.ErrorList { func (a customResourceValidator) Validate(ctx context.Context, obj *unstructured.Unstructured, scale *apiextensions.CustomResourceSubresourceScale) field.ErrorList {
u, ok := obj.(*unstructured.Unstructured) if errs := a.ValidateTypeMeta(ctx, obj); len(errs) > 0 {
if !ok {
return field.ErrorList{field.Invalid(field.NewPath(""), u, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", u))}
}
accessor, err := meta.Accessor(obj)
if err != nil {
return field.ErrorList{field.Invalid(field.NewPath("metadata"), nil, err.Error())}
}
if errs := a.ValidateTypeMeta(ctx, u); len(errs) > 0 {
return errs return errs
} }
var allErrs field.ErrorList var allErrs field.ErrorList
allErrs = append(allErrs, validation.ValidateObjectMetaAccessor(accessor, a.namespaceScoped, validation.NameIsDNSSubdomain, field.NewPath("metadata"))...) allErrs = append(allErrs, validation.ValidateObjectMetaAccessor(obj, a.namespaceScoped, validation.NameIsDNSSubdomain, field.NewPath("metadata"))...)
allErrs = append(allErrs, apiextensionsvalidation.ValidateCustomResource(nil, u.UnstructuredContent(), a.schemaValidator)...) allErrs = append(allErrs, apiextensionsvalidation.ValidateCustomResource(nil, obj.UnstructuredContent(), a.schemaValidator)...)
allErrs = append(allErrs, a.ValidateScaleSpec(ctx, u, scale)...) allErrs = append(allErrs, a.ValidateScaleSpec(ctx, obj, scale)...)
allErrs = append(allErrs, a.ValidateScaleStatus(ctx, u, scale)...) allErrs = append(allErrs, a.ValidateScaleStatus(ctx, obj, scale)...)
return allErrs return allErrs
} }
func (a customResourceValidator) ValidateUpdate(ctx context.Context, obj, old runtime.Object, scale *apiextensions.CustomResourceSubresourceScale) field.ErrorList { func (a customResourceValidator) ValidateUpdate(ctx context.Context, obj, old *unstructured.Unstructured, scale *apiextensions.CustomResourceSubresourceScale) field.ErrorList {
u, ok := obj.(*unstructured.Unstructured) if errs := a.ValidateTypeMeta(ctx, obj); len(errs) > 0 {
if !ok {
return field.ErrorList{field.Invalid(field.NewPath(""), u, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", u))}
}
oldU, ok := old.(*unstructured.Unstructured)
if !ok {
return field.ErrorList{field.Invalid(field.NewPath(""), old, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", u))}
}
objAccessor, err := meta.Accessor(obj)
if err != nil {
return field.ErrorList{field.Invalid(field.NewPath("metadata"), nil, err.Error())}
}
oldAccessor, err := meta.Accessor(old)
if err != nil {
return field.ErrorList{field.Invalid(field.NewPath("metadata"), nil, err.Error())}
}
if errs := a.ValidateTypeMeta(ctx, u); len(errs) > 0 {
return errs return errs
} }
var allErrs field.ErrorList var allErrs field.ErrorList
allErrs = append(allErrs, validation.ValidateObjectMetaAccessorUpdate(objAccessor, oldAccessor, field.NewPath("metadata"))...) allErrs = append(allErrs, validation.ValidateObjectMetaAccessorUpdate(obj, old, field.NewPath("metadata"))...)
allErrs = append(allErrs, apiextensionsvalidation.ValidateCustomResourceUpdate(nil, u.UnstructuredContent(), oldU.UnstructuredContent(), a.schemaValidator)...) allErrs = append(allErrs, apiextensionsvalidation.ValidateCustomResourceUpdate(nil, obj.UnstructuredContent(), old.UnstructuredContent(), a.schemaValidator)...)
allErrs = append(allErrs, a.ValidateScaleSpec(ctx, u, scale)...) allErrs = append(allErrs, a.ValidateScaleSpec(ctx, obj, scale)...)
allErrs = append(allErrs, a.ValidateScaleStatus(ctx, u, scale)...) allErrs = append(allErrs, a.ValidateScaleStatus(ctx, obj, scale)...)
return allErrs return allErrs
} }