mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-02-03 20:40:26 -05:00
wire network group for declarative validation and +k8s:required to IngressClassParametersReference.Name and IngressClassParametersReference.Kind (#134909)
This commit is contained in:
parent
758ef0ffbc
commit
1c24a05ce1
12 changed files with 547 additions and 13 deletions
|
|
@ -38,15 +38,17 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
|
|||
{Group: "certificates.k8s.io", Version: "v1"},
|
||||
{Group: "certificates.k8s.io", Version: "v1alpha1"},
|
||||
{Group: "certificates.k8s.io", Version: "v1beta1"},
|
||||
{Group: "resource.k8s.io", Version: "v1"},
|
||||
{Group: "resource.k8s.io", Version: "v1beta1"},
|
||||
{Group: "resource.k8s.io", Version: "v1beta2"},
|
||||
{Group: "resource.k8s.io", Version: "v1"},
|
||||
{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: "storage.k8s.io", Version: "v1beta1"},
|
||||
{Group: "node.k8s.io", Version: "v1"},
|
||||
{Group: "node.k8s.io", Version: "v1alpha1"},
|
||||
{Group: "node.k8s.io", Version: "v1beta1"},
|
||||
{Group: "network.k8s.io", Version: "v1"},
|
||||
{Group: "network.k8s.io", Version: "v1beta1"},
|
||||
{Group: "autoscaling", Version: "v1"},
|
||||
{Group: "autoscaling", Version: "v1beta1"},
|
||||
{Group: "autoscaling", Version: "v1beta2"},
|
||||
|
|
@ -74,9 +76,6 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
|
|||
allRules := append([]field.NormalizationRule{}, resourcevalidation.ResourceNormalizationRules...)
|
||||
allRules = append(allRules, nodevalidation.NodeNormalizationRules...)
|
||||
opts = append(opts, WithNormalizationRules(allRules...))
|
||||
if gv.Group == "autoscaling" {
|
||||
opts = append(opts, WithIgnoreObjectConversionErrors())
|
||||
}
|
||||
|
||||
VerifyVersionedValidationEquivalence(t, obj, nil, opts...)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,5 +20,7 @@ limitations under the License.
|
|||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:defaulter-gen-input=k8s.io/api/networking/v1
|
||||
// +groupName=networking.k8s.io
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/networking/v1
|
||||
|
||||
package v1
|
||||
|
|
|
|||
150
pkg/apis/networking/v1/zz_generated.validations.go
generated
Normal file
150
pkg/apis/networking/v1/zz_generated.validations.go
generated
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//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"
|
||||
|
||||
networkingv1 "k8s.io/api/networking/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 IngressClass
|
||||
scheme.AddValidationFunc((*networkingv1.IngressClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_IngressClass(ctx, op, nil /* fldPath */, obj.(*networkingv1.IngressClass), safe.Cast[*networkingv1.IngressClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate_IngressClass validates an instance of IngressClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.IngressClass) (errs field.ErrorList) {
|
||||
// field networkingv1.IngressClass.TypeMeta has no validation
|
||||
// field networkingv1.IngressClass.ObjectMeta has no validation
|
||||
|
||||
// field networkingv1.IngressClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *networkingv1.IngressClassSpec, 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_IngressClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *networkingv1.IngressClass) *networkingv1.IngressClassSpec { return &oldObj.Spec }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_IngressClassParametersReference validates an instance of IngressClassParametersReference according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClassParametersReference(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.IngressClassParametersReference) (errs field.ErrorList) {
|
||||
// field networkingv1.IngressClassParametersReference.APIGroup has no validation
|
||||
|
||||
// field networkingv1.IngressClassParametersReference.Kind
|
||||
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.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("kind"), &obj.Kind, safe.Field(oldObj, func(oldObj *networkingv1.IngressClassParametersReference) *string { return &oldObj.Kind }), oldObj != nil)...)
|
||||
|
||||
// field networkingv1.IngressClassParametersReference.Name
|
||||
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.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("name"), &obj.Name, safe.Field(oldObj, func(oldObj *networkingv1.IngressClassParametersReference) *string { return &oldObj.Name }), oldObj != nil)...)
|
||||
|
||||
// field networkingv1.IngressClassParametersReference.Scope has no validation
|
||||
// field networkingv1.IngressClassParametersReference.Namespace has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_IngressClassSpec validates an instance of IngressClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.IngressClassSpec) (errs field.ErrorList) {
|
||||
// field networkingv1.IngressClassSpec.Controller has no validation
|
||||
|
||||
// field networkingv1.IngressClassSpec.Parameters
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *networkingv1.IngressClassParametersReference, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_IngressClassParametersReference(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("parameters"), obj.Parameters, safe.Field(oldObj, func(oldObj *networkingv1.IngressClassSpec) *networkingv1.IngressClassParametersReference {
|
||||
return oldObj.Parameters
|
||||
}), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
|
@ -20,5 +20,7 @@ limitations under the License.
|
|||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:defaulter-gen-input=k8s.io/api/networking/v1beta1
|
||||
// +groupName=networking.k8s.io
|
||||
// +k8s:validation-gen=TypeMeta
|
||||
// +k8s:validation-gen-input=k8s.io/api/networking/v1beta1
|
||||
|
||||
package v1beta1
|
||||
|
|
|
|||
150
pkg/apis/networking/v1beta1/zz_generated.validations.go
generated
Normal file
150
pkg/apis/networking/v1beta1/zz_generated.validations.go
generated
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//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"
|
||||
|
||||
networkingv1beta1 "k8s.io/api/networking/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 IngressClass
|
||||
scheme.AddValidationFunc((*networkingv1beta1.IngressClass)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList {
|
||||
switch op.Request.SubresourcePath() {
|
||||
case "/":
|
||||
return Validate_IngressClass(ctx, op, nil /* fldPath */, obj.(*networkingv1beta1.IngressClass), safe.Cast[*networkingv1beta1.IngressClass](oldObj))
|
||||
}
|
||||
return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate_IngressClass validates an instance of IngressClass according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClass(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1beta1.IngressClass) (errs field.ErrorList) {
|
||||
// field networkingv1beta1.IngressClass.TypeMeta has no validation
|
||||
// field networkingv1beta1.IngressClass.ObjectMeta has no validation
|
||||
|
||||
// field networkingv1beta1.IngressClass.Spec
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *networkingv1beta1.IngressClassSpec, 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_IngressClassSpec(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *networkingv1beta1.IngressClass) *networkingv1beta1.IngressClassSpec { return &oldObj.Spec }), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_IngressClassParametersReference validates an instance of IngressClassParametersReference according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClassParametersReference(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1beta1.IngressClassParametersReference) (errs field.ErrorList) {
|
||||
// field networkingv1beta1.IngressClassParametersReference.APIGroup has no validation
|
||||
|
||||
// field networkingv1beta1.IngressClassParametersReference.Kind
|
||||
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.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("kind"), &obj.Kind, safe.Field(oldObj, func(oldObj *networkingv1beta1.IngressClassParametersReference) *string { return &oldObj.Kind }), oldObj != nil)...)
|
||||
|
||||
// field networkingv1beta1.IngressClassParametersReference.Name
|
||||
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.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}(fldPath.Child("name"), &obj.Name, safe.Field(oldObj, func(oldObj *networkingv1beta1.IngressClassParametersReference) *string { return &oldObj.Name }), oldObj != nil)...)
|
||||
|
||||
// field networkingv1beta1.IngressClassParametersReference.Scope has no validation
|
||||
// field networkingv1beta1.IngressClassParametersReference.Namespace has no validation
|
||||
return errs
|
||||
}
|
||||
|
||||
// Validate_IngressClassSpec validates an instance of IngressClassSpec according
|
||||
// to declarative validation rules in the API schema.
|
||||
func Validate_IngressClassSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1beta1.IngressClassSpec) (errs field.ErrorList) {
|
||||
// field networkingv1beta1.IngressClassSpec.Controller has no validation
|
||||
|
||||
// field networkingv1beta1.IngressClassSpec.Parameters
|
||||
errs = append(errs,
|
||||
func(fldPath *field.Path, obj, oldObj *networkingv1beta1.IngressClassParametersReference, oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
|
||||
return nil
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
// call the type's validation function
|
||||
errs = append(errs, Validate_IngressClassParametersReference(ctx, op, fldPath, obj, oldObj)...)
|
||||
return
|
||||
}(fldPath.Child("parameters"), obj.Parameters, safe.Field(oldObj, func(oldObj *networkingv1beta1.IngressClassSpec) *networkingv1beta1.IngressClassParametersReference {
|
||||
return oldObj.Parameters
|
||||
}), oldObj != nil)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
|
@ -632,11 +632,27 @@ func validateIngressClassParametersReference(params *networking.IngressClassPara
|
|||
return allErrs
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateIngressTypedLocalObjectReference(&api.TypedLocalObjectReference{
|
||||
APIGroup: params.APIGroup,
|
||||
Kind: params.Kind,
|
||||
Name: params.Name,
|
||||
}, fldPath)...)
|
||||
if params.APIGroup != nil {
|
||||
for _, msg := range validation.IsDNS1123Subdomain(*params.APIGroup) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("apiGroup"), *params.APIGroup, msg))
|
||||
}
|
||||
}
|
||||
|
||||
if params.Kind == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")).MarkCoveredByDeclarative()
|
||||
} else {
|
||||
for _, msg := range pathvalidation.IsValidPathSegmentName(params.Kind) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), params.Kind, msg))
|
||||
}
|
||||
}
|
||||
|
||||
if params.Name == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")).MarkCoveredByDeclarative()
|
||||
} else {
|
||||
for _, msg := range pathvalidation.IsValidPathSegmentName(params.Name) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), params.Name, msg))
|
||||
}
|
||||
}
|
||||
|
||||
if params.Scope == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("scope"), ""))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
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 ingressclass
|
||||
|
||||
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"
|
||||
networking "k8s.io/kubernetes/pkg/apis/networking"
|
||||
)
|
||||
|
||||
var apiVersions = []string{"v1", "v1beta1"}
|
||||
|
||||
func TestDeclarativeValidateParameter(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(
|
||||
genericapirequest.NewDefaultContext(),
|
||||
&genericapirequest.RequestInfo{
|
||||
APIGroup: "networking.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
Resource: "ingressclasses",
|
||||
IsResourceRequest: true,
|
||||
Verb: "create",
|
||||
},
|
||||
)
|
||||
|
||||
testCases := map[string]struct {
|
||||
input networking.IngressClass
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"valid": {
|
||||
input: mkValidIngressClass(),
|
||||
},
|
||||
"nil parameters": {
|
||||
input: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.Spec.Parameters = nil
|
||||
}),
|
||||
},
|
||||
"missing parameter name": {
|
||||
input: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.Spec.Parameters.Name = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Required(field.NewPath("spec", "parameters", "name"), "")},
|
||||
},
|
||||
"missing parameter kind": {
|
||||
input: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.Spec.Parameters.Kind = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Required(field.NewPath("spec", "parameters", "kind"), ""),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
apitesting.VerifyValidationEquivalence(
|
||||
t,
|
||||
ctx,
|
||||
&tc.input,
|
||||
Strategy.Validate,
|
||||
tc.expectedErrs,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeclarativeValidateUpdateParameters(t *testing.T) {
|
||||
for _, apiVersion := range apiVersions {
|
||||
t.Run(apiVersion, func(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
oldObj networking.IngressClass
|
||||
updateObj networking.IngressClass
|
||||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"valid update": {
|
||||
oldObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
}),
|
||||
updateObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
}),
|
||||
},
|
||||
"nil parameters update": {
|
||||
oldObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
}),
|
||||
updateObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
obj.Spec.Parameters = nil
|
||||
}),
|
||||
},
|
||||
"update fails when parameters name is cleared": {
|
||||
oldObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
}),
|
||||
updateObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
obj.Spec.Parameters.Name = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Required(field.NewPath("spec", "parameters", "name"), ""),
|
||||
},
|
||||
},
|
||||
"update fails when parameters kind is cleared": {
|
||||
oldObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
}),
|
||||
updateObj: mkValidIngressClass(func(obj *networking.IngressClass) {
|
||||
obj.ResourceVersion = "1"
|
||||
obj.Spec.Parameters.Kind = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Required(field.NewPath("spec", "parameters", "kind"), ""),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(
|
||||
genericapirequest.NewDefaultContext(),
|
||||
&genericapirequest.RequestInfo{
|
||||
APIPrefix: "apis",
|
||||
APIGroup: "networking.k8s.io",
|
||||
APIVersion: apiVersion,
|
||||
Resource: "ingressclasses",
|
||||
Name: "valid-ingress-class",
|
||||
IsResourceRequest: true,
|
||||
Verb: "update",
|
||||
},
|
||||
)
|
||||
apitesting.VerifyUpdateValidationEquivalence(
|
||||
t,
|
||||
ctx,
|
||||
&tc.updateObj,
|
||||
&tc.oldObj,
|
||||
Strategy.ValidateUpdate,
|
||||
tc.expectedErrs,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mkValidIngressClass(tweaks ...func(obj *networking.IngressClass)) networking.IngressClass {
|
||||
apiGroup := "example.com"
|
||||
scope := networking.IngressClassParametersReferenceScopeCluster
|
||||
|
||||
obj := networking.IngressClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "valid-ingress-class",
|
||||
},
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "example.com/ingress-controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
APIGroup: &apiGroup,
|
||||
Kind: "IngressParameters",
|
||||
Name: "valid-params",
|
||||
Scope: &scope,
|
||||
Namespace: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tweak := range tweaks {
|
||||
tweak(&obj)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ package ingressclass
|
|||
|
||||
import (
|
||||
"context"
|
||||
"k8s.io/apimachinery/pkg/api/operation"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -67,7 +69,8 @@ func (ingressClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runti
|
|||
// Validate validates a new IngressClass.
|
||||
func (ingressClassStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
ingressClass := obj.(*networking.IngressClass)
|
||||
return validation.ValidateIngressClass(ingressClass)
|
||||
allErrs := validation.ValidateIngressClass(ingressClass)
|
||||
return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, ingressClass, nil, allErrs, operation.Create)
|
||||
}
|
||||
|
||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||
|
|
@ -90,7 +93,8 @@ func (ingressClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
|
|||
newIngressClass := obj.(*networking.IngressClass)
|
||||
oldIngressClass := old.(*networking.IngressClass)
|
||||
|
||||
return validation.ValidateIngressClassUpdate(newIngressClass, oldIngressClass)
|
||||
allErrs := validation.ValidateIngressClassUpdate(newIngressClass, oldIngressClass)
|
||||
return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newIngressClass, oldIngressClass, allErrs, operation.Update)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
|
|
|
|||
|
|
@ -199,9 +199,13 @@ message IngressClassParametersReference {
|
|||
optional string aPIGroup = 1;
|
||||
|
||||
// kind is the type of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
optional string kind = 2;
|
||||
|
||||
// name is the name of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
optional string name = 3;
|
||||
|
||||
// scope represents if this refers to a cluster or namespace scoped resource.
|
||||
|
|
@ -230,6 +234,7 @@ message IngressClassSpec {
|
|||
// configuration for the controller. This is optional if the controller does
|
||||
// not require extra parameters.
|
||||
// +optional
|
||||
// +k8s:optional
|
||||
optional IngressClassParametersReference parameters = 2;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -583,6 +583,7 @@ type IngressClassSpec struct {
|
|||
// configuration for the controller. This is optional if the controller does
|
||||
// not require extra parameters.
|
||||
// +optional
|
||||
// +k8s:optional
|
||||
Parameters *IngressClassParametersReference `json:"parameters,omitempty" protobuf:"bytes,2,opt,name=parameters"`
|
||||
}
|
||||
|
||||
|
|
@ -605,9 +606,13 @@ type IngressClassParametersReference struct {
|
|||
APIGroup *string `json:"apiGroup,omitempty" protobuf:"bytes,1,opt,name=aPIGroup"`
|
||||
|
||||
// kind is the type of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
|
||||
|
||||
// name is the name of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
||||
|
||||
// scope represents if this refers to a cluster or namespace scoped resource.
|
||||
|
|
|
|||
|
|
@ -186,9 +186,13 @@ message IngressClassParametersReference {
|
|||
optional string aPIGroup = 1;
|
||||
|
||||
// kind is the type of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
optional string kind = 2;
|
||||
|
||||
// name is the name of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
optional string name = 3;
|
||||
|
||||
// scope represents if this refers to a cluster or namespace scoped resource.
|
||||
|
|
@ -216,6 +220,7 @@ message IngressClassSpec {
|
|||
// configuration for the controller. This is optional if the controller does
|
||||
// not require extra parameters.
|
||||
// +optional
|
||||
// +k8s:optional
|
||||
optional IngressClassParametersReference parameters = 2;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ type IngressClassSpec struct {
|
|||
// configuration for the controller. This is optional if the controller does
|
||||
// not require extra parameters.
|
||||
// +optional
|
||||
// +k8s:optional
|
||||
Parameters *IngressClassParametersReference `json:"parameters,omitempty" protobuf:"bytes,2,opt,name=parameters"`
|
||||
}
|
||||
|
||||
|
|
@ -390,9 +391,13 @@ type IngressClassParametersReference struct {
|
|||
APIGroup *string `json:"apiGroup,omitempty" protobuf:"bytes,1,opt,name=aPIGroup"`
|
||||
|
||||
// kind is the type of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
|
||||
|
||||
// name is the name of resource being referenced.
|
||||
// +required
|
||||
// +k8s:required
|
||||
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
||||
|
||||
// scope represents if this refers to a cluster or namespace scoped resource.
|
||||
|
|
|
|||
Loading…
Reference in a new issue