mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 20:00:07 +00:00
DRA: adding tag to node module
move DRA to a update method fix boilerplate code apply node normalize code at fuzz logic adding normalization fix fix nit
This commit is contained in:
@@ -23,7 +23,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
nodevalidation "k8s.io/kubernetes/pkg/apis/node/validation"
|
||||
resourcevalidation "k8s.io/kubernetes/pkg/apis/resource/validation"
|
||||
)
|
||||
|
||||
@@ -42,6 +44,9 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
|
||||
{Group: "storage.k8s.io", Version: "v1"},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1"},
|
||||
{Group: "storage.k8s.io", Version: "v1alpha1"},
|
||||
{Group: "node.k8s.io", Version: "v1beta1"},
|
||||
{Group: "node.k8s.io", Version: "v1"},
|
||||
{Group: "node.k8s.io", Version: "v1alpha1"},
|
||||
}
|
||||
|
||||
fuzzIters := *roundtrip.FuzzIters / 10 // TODO: Find a better way to manage test running time
|
||||
@@ -59,7 +64,12 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
|
||||
f.Fill(obj)
|
||||
|
||||
var opts []ValidationTestConfig
|
||||
opts = append(opts, WithNormalizationRules(resourcevalidation.ResourceNormalizationRules...))
|
||||
// TODO(API group level configuration): Consider configuring normalization rules at the
|
||||
// API group level to avoid potential collisions when multiple rule sets are combined.
|
||||
// This would allow each API group to register its own normalization rules independently.
|
||||
allRules := append([]field.NormalizationRule{}, resourcevalidation.ResourceNormalizationRules...)
|
||||
allRules = append(allRules, nodevalidation.NodeNormalizationRules...)
|
||||
opts = append(opts, WithNormalizationRules(allRules...))
|
||||
|
||||
VerifyVersionedValidationEquivalence(t, obj, nil, opts...)
|
||||
|
||||
|
||||
@@ -19,4 +19,7 @@ limitations under the License.
|
||||
|
||||
// +groupName=node.k8s.io
|
||||
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/node/v1
|
||||
|
||||
package v1
|
||||
|
||||
111
pkg/apis/node/v1/zz_generated.validations.go
generated
Normal file
111
pkg/apis/node/v1/zz_generated.validations.go
generated
Normal file
@@ -0,0 +1,111 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
|
||||
nodev1 "k8s.io/api/node/v1"
|
||||
equality "k8s.io/apimachinery/pkg/api/equality"
|
||||
operation "k8s.io/apimachinery/pkg/api/operation"
|
||||
safe "k8s.io/apimachinery/pkg/api/safe"
|
||||
validate "k8s.io/apimachinery/pkg/api/validate"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
field "k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type RuntimeClass
|
||||
scheme.AddValidationFunc((*nodev1.RuntimeClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClass(ctx, op, nil /* fldPath */, obj.(*nodev1.RuntimeClass), safe.Cast[*nodev1.RuntimeClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type RuntimeClassList
|
||||
scheme.AddValidationFunc((*nodev1.RuntimeClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClassList(ctx, op, nil /* fldPath */, obj.(*nodev1.RuntimeClassList), safe.Cast[*nodev1.RuntimeClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate_RuntimeClass validates an instance of RuntimeClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1.RuntimeClass) (errs field.ErrorList) {
|
||||
// field nodev1.RuntimeClass.TypeMeta has no validation
|
||||
// field nodev1.RuntimeClass.ObjectMeta has no validation
|
||||
|
||||
// field nodev1.RuntimeClass.Handler
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.Immutable(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
errs = append(errs, validate.ShortName(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("handler"), &obj.Handler, safe.Field(oldObj, func(oldObj *nodev1.RuntimeClass) *string { return &oldObj.Handler }), oldObj != nil)...)
|
||||
|
||||
// field nodev1.RuntimeClass.Overhead has no validation
|
||||
// field nodev1.RuntimeClass.Scheduling has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_RuntimeClassList validates an instance of RuntimeClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1.RuntimeClassList) (errs field.ErrorList) {
|
||||
// field nodev1.RuntimeClassList.TypeMeta has no validation
|
||||
// field nodev1.RuntimeClassList.ListMeta has no validation
|
||||
|
||||
// field nodev1.RuntimeClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []nodev1.RuntimeClass, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_RuntimeClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *nodev1.RuntimeClassList) []nodev1.RuntimeClass { return oldObj.Items }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
@@ -19,4 +19,7 @@ limitations under the License.
|
||||
|
||||
// +groupName=node.k8s.io
|
||||
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/node/v1alpha1
|
||||
|
||||
package v1alpha1
|
||||
|
||||
129
pkg/apis/node/v1alpha1/zz_generated.validations.go
generated
Normal file
129
pkg/apis/node/v1alpha1/zz_generated.validations.go
generated
Normal file
@@ -0,0 +1,129 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
|
||||
nodev1alpha1 "k8s.io/api/node/v1alpha1"
|
||||
equality "k8s.io/apimachinery/pkg/api/equality"
|
||||
operation "k8s.io/apimachinery/pkg/api/operation"
|
||||
safe "k8s.io/apimachinery/pkg/api/safe"
|
||||
validate "k8s.io/apimachinery/pkg/api/validate"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
field "k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type RuntimeClass
|
||||
scheme.AddValidationFunc((*nodev1alpha1.RuntimeClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClass(ctx, op, nil /* fldPath */, obj.(*nodev1alpha1.RuntimeClass), safe.Cast[*nodev1alpha1.RuntimeClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type RuntimeClassList
|
||||
scheme.AddValidationFunc((*nodev1alpha1.RuntimeClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClassList(ctx, op, nil /* fldPath */, obj.(*nodev1alpha1.RuntimeClassList), safe.Cast[*nodev1alpha1.RuntimeClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate_RuntimeClass validates an instance of RuntimeClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1alpha1.RuntimeClass) (errs field.ErrorList) {
|
||||
// field nodev1alpha1.RuntimeClass.TypeMeta has no validation
|
||||
// field nodev1alpha1.RuntimeClass.ObjectMeta has no validation
|
||||
|
||||
// field nodev1alpha1.RuntimeClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *nodev1alpha1.RuntimeClassSpec, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_RuntimeClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *nodev1alpha1.RuntimeClass) *nodev1alpha1.RuntimeClassSpec { return &oldObj.Spec }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_RuntimeClassList validates an instance of RuntimeClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1alpha1.RuntimeClassList) (errs field.ErrorList) {
|
||||
// field nodev1alpha1.RuntimeClassList.TypeMeta has no validation
|
||||
// field nodev1alpha1.RuntimeClassList.ListMeta has no validation
|
||||
|
||||
// field nodev1alpha1.RuntimeClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []nodev1alpha1.RuntimeClass, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_RuntimeClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *nodev1alpha1.RuntimeClassList) []nodev1alpha1.RuntimeClass { return oldObj.Items }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_RuntimeClassSpec validates an instance of RuntimeClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1alpha1.RuntimeClassSpec) (errs field.ErrorList) {
|
||||
// field nodev1alpha1.RuntimeClassSpec.RuntimeHandler
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.Immutable(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
errs = append(errs, validate.ShortName(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("runtimeHandler"), &obj.RuntimeHandler, safe.Field(oldObj, func(oldObj *nodev1alpha1.RuntimeClassSpec) *string { return &oldObj.RuntimeHandler }), oldObj != nil)...)
|
||||
|
||||
// field nodev1alpha1.RuntimeClassSpec.Overhead has no validation
|
||||
// field nodev1alpha1.RuntimeClassSpec.Scheduling has no validation
|
||||
return errs
|
||||
}
|
||||
@@ -19,4 +19,7 @@ limitations under the License.
|
||||
|
||||
// +groupName=node.k8s.io
|
||||
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/node/v1beta1
|
||||
|
||||
package v1beta1
|
||||
|
||||
111
pkg/apis/node/v1beta1/zz_generated.validations.go
generated
Normal file
111
pkg/apis/node/v1beta1/zz_generated.validations.go
generated
Normal file
@@ -0,0 +1,111 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
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 validation-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
|
||||
nodev1beta1 "k8s.io/api/node/v1beta1"
|
||||
equality "k8s.io/apimachinery/pkg/api/equality"
|
||||
operation "k8s.io/apimachinery/pkg/api/operation"
|
||||
safe "k8s.io/apimachinery/pkg/api/safe"
|
||||
validate "k8s.io/apimachinery/pkg/api/validate"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
field "k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func init() { localSchemeBuilder.Register(RegisterValidations) }
|
||||
|
||||
// RegisterValidations adds validation functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterValidations(scheme *runtime.Scheme) error {
|
||||
// type RuntimeClass
|
||||
scheme.AddValidationFunc((*nodev1beta1.RuntimeClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClass(ctx, op, nil /* fldPath */, obj.(*nodev1beta1.RuntimeClass), safe.Cast[*nodev1beta1.RuntimeClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
// type RuntimeClassList
|
||||
scheme.AddValidationFunc((*nodev1beta1.RuntimeClassList)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_RuntimeClassList(ctx, op, nil /* fldPath */, obj.(*nodev1beta1.RuntimeClassList), safe.Cast[*nodev1beta1.RuntimeClassList](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate_RuntimeClass validates an instance of RuntimeClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1beta1.RuntimeClass) (errs field.ErrorList) {
|
||||
// field nodev1beta1.RuntimeClass.TypeMeta has no validation
|
||||
// field nodev1beta1.RuntimeClass.ObjectMeta has no validation
|
||||
|
||||
// field nodev1beta1.RuntimeClass.Handler
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.Immutable(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
errs = append(errs, validate.ShortName(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("handler"), &obj.Handler, safe.Field(oldObj, func(oldObj *nodev1beta1.RuntimeClass) *string { return &oldObj.Handler }), oldObj != nil)...)
|
||||
|
||||
// field nodev1beta1.RuntimeClass.Overhead has no validation
|
||||
// field nodev1beta1.RuntimeClass.Scheduling has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_RuntimeClassList validates an instance of RuntimeClassList according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_RuntimeClassList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *nodev1beta1.RuntimeClassList) (errs field.ErrorList) {
|
||||
// field nodev1beta1.RuntimeClassList.TypeMeta has no validation
|
||||
// field nodev1beta1.RuntimeClassList.ListMeta has no validation
|
||||
|
||||
// field nodev1beta1.RuntimeClassList.Items
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj []nodev1beta1.RuntimeClass, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// iterate the list and call the type's validation function
|
||||
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_RuntimeClass)...)
|
||||
return
|
||||
}(fldPath.Child("items"), obj.Items, safe.Field(oldObj, func(oldObj *nodev1beta1.RuntimeClassList) []nodev1beta1.RuntimeClass { return oldObj.Items }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
@@ -23,14 +23,24 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
corevalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/node"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Define normalization rules to handle field name differences across API versions
|
||||
// v1alpha1 uses "spec.runtimeHandler" while v1/v1beta1 use "handler"
|
||||
var NodeNormalizationRules = []field.NormalizationRule{
|
||||
{
|
||||
Regexp: regexp.MustCompile(`^spec\.runtimeHandler(.*)$`),
|
||||
Replacement: "handler$1",
|
||||
},
|
||||
}
|
||||
|
||||
// ValidateRuntimeClass validates the RuntimeClass
|
||||
func ValidateRuntimeClass(rc *node.RuntimeClass) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMeta(&rc.ObjectMeta, false, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
|
||||
|
||||
for _, msg := range apivalidation.NameIsDNSLabel(rc.Handler, false) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("handler"), rc.Handler, msg))
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("handler"), rc.Handler, msg)).MarkCoveredByDeclarative().WithOrigin("format=k8s-short-name")
|
||||
}
|
||||
|
||||
if rc.Overhead != nil {
|
||||
@@ -47,7 +57,7 @@ func ValidateRuntimeClass(rc *node.RuntimeClass) field.ErrorList {
|
||||
func ValidateRuntimeClassUpdate(new, old *node.RuntimeClass) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMetaUpdate(&new.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))
|
||||
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(new.Handler, old.Handler, field.NewPath("handler"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateImmutableField(new.Handler, old.Handler, field.NewPath("handler"))...).MarkCoveredByDeclarative().WithOrigin("immutable")
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
130
pkg/registry/node/runtimeclass/declarative_validation_test.go
Normal file
130
pkg/registry/node/runtimeclass/declarative_validation_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package runtimeclass
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
node "k8s.io/kubernetes/pkg/apis/node"
|
||||
"k8s.io/kubernetes/pkg/apis/node/validation"
|
||||
)
|
||||
|
||||
var apiVersions = []string{"v1", "v1beta1", "v1alpha1"}
|
||||
|
||||
func mkRuntimeClassHandlerOnly(tweaks ...func(*node.RuntimeClass)) node.RuntimeClass {
|
||||
rc := node.RuntimeClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myrc",
|
||||
},
|
||||
Handler: "runc",
|
||||
}
|
||||
for _, f := range tweaks {
|
||||
f(&rc)
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
func TestRuntimeClass_DeclarativeValidate_Create(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(
|
||||
genericapirequest.NewDefaultContext(),
|
||||
&genericapirequest.RequestInfo{
|
||||
APIGroup: "node.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
},
|
||||
)
|
||||
|
||||
tests := map[string]struct {
|
||||
obj node.RuntimeClass
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"valid handler": {
|
||||
obj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) {
|
||||
rc.Handler = "test"
|
||||
}),
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"invalid handler dns label": {
|
||||
obj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) {
|
||||
rc.Handler = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("handler"),
|
||||
"", "").WithOrigin("format=k8s-short-name"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
apitesting.VerifyValidationEquivalence(t, ctx, &tc.obj, Strategy.Validate, tc.expectedErrs,
|
||||
apitesting.WithNormalizationRules(validation.NodeNormalizationRules...))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntimeClass_DeclarativeValidate_Update(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(
|
||||
genericapirequest.NewDefaultContext(),
|
||||
&genericapirequest.RequestInfo{
|
||||
APIGroup: "node.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
},
|
||||
)
|
||||
|
||||
tests := map[string]struct {
|
||||
oldObj, newObj node.RuntimeClass
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"no-op update": {
|
||||
oldObj: mkRuntimeClassHandlerOnly(),
|
||||
newObj: mkRuntimeClassHandlerOnly(),
|
||||
expectedErrs: field.ErrorList{},
|
||||
},
|
||||
"handler changed (immutable)": {
|
||||
oldObj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) {
|
||||
rc.Handler = "runc"
|
||||
}),
|
||||
newObj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) {
|
||||
rc.Handler = "asadsasdas"
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("handler"), "",
|
||||
"").WithOrigin("immutable"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
tc.oldObj.ObjectMeta.ResourceVersion = "1"
|
||||
tc.newObj.ObjectMeta.ResourceVersion = "1"
|
||||
apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.newObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithNormalizationRules(validation.NodeNormalizationRules...))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package runtimeclass
|
||||
|
||||
import (
|
||||
"context"
|
||||
"k8s.io/apimachinery/pkg/api/operation"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
@@ -70,7 +71,9 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
// Validate validates a new RuntimeClass. Validation must check for a correct signature.
|
||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
runtimeClass := obj.(*node.RuntimeClass)
|
||||
return validation.ValidateRuntimeClass(runtimeClass)
|
||||
allErrs := validation.ValidateRuntimeClass(runtimeClass)
|
||||
return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, runtimeClass, nil, allErrs, operation.Create, rest.WithNormalizationRules(validation.NodeNormalizationRules))
|
||||
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
@@ -87,7 +90,9 @@ func (strategy) Canonicalize(obj runtime.Object) {
|
||||
func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
newObj := obj.(*node.RuntimeClass)
|
||||
errorList := validation.ValidateRuntimeClass(newObj)
|
||||
return append(errorList, validation.ValidateRuntimeClassUpdate(newObj, old.(*node.RuntimeClass))...)
|
||||
errorList = append(errorList, validation.ValidateRuntimeClassUpdate(newObj, old.(*node.RuntimeClass))...)
|
||||
return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newObj, old, errorList, operation.Update, rest.WithNormalizationRules(validation.NodeNormalizationRules))
|
||||
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
|
||||
@@ -59,6 +59,8 @@ message RuntimeClass {
|
||||
// in a pod.
|
||||
// The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements,
|
||||
// and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
optional string handler = 2;
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
@@ -50,6 +50,8 @@ type RuntimeClass struct {
|
||||
// in a pod.
|
||||
// The Handler must be lowercase, conform to the DNS Label (RFC 1123) requirements,
|
||||
// and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
Handler string `json:"handler" protobuf:"bytes,2,opt,name=handler"`
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
@@ -80,6 +80,8 @@ message RuntimeClassSpec {
|
||||
// in a pod.
|
||||
// The runtimeHandler must be lowercase, conform to the DNS Label (RFC 1123)
|
||||
// requirements, and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
optional string runtimeHandler = 1;
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
@@ -59,6 +59,8 @@ type RuntimeClassSpec struct {
|
||||
// in a pod.
|
||||
// The runtimeHandler must be lowercase, conform to the DNS Label (RFC 1123)
|
||||
// requirements, and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
RuntimeHandler string `json:"runtimeHandler" protobuf:"bytes,1,opt,name=runtimeHandler"`
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
@@ -59,6 +59,8 @@ message RuntimeClass {
|
||||
// in a pod.
|
||||
// The handler must be lowercase, conform to the DNS Label (RFC 1123) requirements,
|
||||
// and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
optional string handler = 2;
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
@@ -51,6 +51,8 @@ type RuntimeClass struct {
|
||||
// in a pod.
|
||||
// The handler must be lowercase, conform to the DNS Label (RFC 1123) requirements,
|
||||
// and is immutable.
|
||||
// +k8s:format="k8s-short-name"
|
||||
// +k8s:immutable
|
||||
Handler string `json:"handler" protobuf:"bytes,2,opt,name=handler"`
|
||||
|
||||
// overhead represents the resource overhead associated with running a pod for a
|
||||
|
||||
Reference in New Issue
Block a user