From bc17031d19fea7230fdc6d22bce956df5b7fe66e Mon Sep 17 00:00:00 2001 From: darshansreenivas Date: Wed, 10 Dec 2025 21:26:49 -0800 Subject: [PATCH] network: migrate CIDR validation to DV Co-authored-by: Abhishek Srivastava --- .../networking/v1/zz_generated.validations.go | 163 +++++++++++++ pkg/apis/networking/validation/validation.go | 2 +- .../declarative_validation_test.go | 214 ++++++++++++++++++ .../networking/networkpolicy/strategy.go | 11 +- .../api/extensions/v1beta1/generated.proto | 3 + .../k8s.io/api/extensions/v1beta1/types.go | 3 + .../v1beta1/zz_generated.validations.go | 158 +++++++++++++ .../k8s.io/api/networking/v1/generated.proto | 3 + staging/src/k8s.io/api/networking/v1/types.go | 3 + 9 files changed, 555 insertions(+), 5 deletions(-) create mode 100644 pkg/registry/networking/networkpolicy/declarative_validation_test.go diff --git a/pkg/apis/networking/v1/zz_generated.validations.go b/pkg/apis/networking/v1/zz_generated.validations.go index b2186f291e3..24b094a36fe 100644 --- a/pkg/apis/networking/v1/zz_generated.validations.go +++ b/pkg/apis/networking/v1/zz_generated.validations.go @@ -47,9 +47,43 @@ func RegisterValidations(scheme *runtime.Scheme) error { } return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} }) + // type NetworkPolicy + scheme.AddValidationFunc((*networkingv1.NetworkPolicy)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_NetworkPolicy(ctx, op, nil /* fldPath */, obj.(*networkingv1.NetworkPolicy), safe.Cast[*networkingv1.NetworkPolicy](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) return nil } +// Validate_IPBlock validates an instance of IPBlock according +// to declarative validation rules in the API schema. +func Validate_IPBlock(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.IPBlock) (errs field.ErrorList) { + // field networkingv1.IPBlock.CIDR + 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("cidr"), &obj.CIDR, safe.Field(oldObj, func(oldObj *networkingv1.IPBlock) *string { return &oldObj.CIDR }), oldObj != nil)...) + + // field networkingv1.IPBlock.Except has no validation + return errs +} + // 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) { @@ -148,3 +182,132 @@ func Validate_IngressClassSpec(ctx context.Context, op operation.Operation, fldP return errs } + +// Validate_NetworkPolicy validates an instance of NetworkPolicy according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicy(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicy) (errs field.ErrorList) { + // field networkingv1.NetworkPolicy.TypeMeta has no validation + // field networkingv1.NetworkPolicy.ObjectMeta has no validation + + // field networkingv1.NetworkPolicy.Spec + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicySpec, 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_NetworkPolicySpec(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicy) *networkingv1.NetworkPolicySpec { return &oldObj.Spec }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyEgressRule validates an instance of NetworkPolicyEgressRule according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyEgressRule(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicyEgressRule) (errs field.ErrorList) { + // field networkingv1.NetworkPolicyEgressRule.Ports has no validation + + // field networkingv1.NetworkPolicyEgressRule.To + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []networkingv1.NetworkPolicyPeer, 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_NetworkPolicyPeer)...) + return + }(fldPath.Child("to"), obj.To, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicyEgressRule) []networkingv1.NetworkPolicyPeer { return oldObj.To }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyIngressRule validates an instance of NetworkPolicyIngressRule according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyIngressRule(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicyIngressRule) (errs field.ErrorList) { + // field networkingv1.NetworkPolicyIngressRule.Ports has no validation + + // field networkingv1.NetworkPolicyIngressRule.From + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []networkingv1.NetworkPolicyPeer, 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_NetworkPolicyPeer)...) + return + }(fldPath.Child("from"), obj.From, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicyIngressRule) []networkingv1.NetworkPolicyPeer { + return oldObj.From + }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyPeer validates an instance of NetworkPolicyPeer according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyPeer(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicyPeer) (errs field.ErrorList) { + // field networkingv1.NetworkPolicyPeer.PodSelector has no validation + // field networkingv1.NetworkPolicyPeer.NamespaceSelector has no validation + + // field networkingv1.NetworkPolicyPeer.IPBlock + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *networkingv1.IPBlock, 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_IPBlock(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("ipBlock"), obj.IPBlock, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicyPeer) *networkingv1.IPBlock { return oldObj.IPBlock }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicySpec validates an instance of NetworkPolicySpec according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicySpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *networkingv1.NetworkPolicySpec) (errs field.ErrorList) { + // field networkingv1.NetworkPolicySpec.PodSelector has no validation + + // field networkingv1.NetworkPolicySpec.Ingress + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []networkingv1.NetworkPolicyIngressRule, 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_NetworkPolicyIngressRule)...) + return + }(fldPath.Child("ingress"), obj.Ingress, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicySpec) []networkingv1.NetworkPolicyIngressRule { + return oldObj.Ingress + }), oldObj != nil)...) + + // field networkingv1.NetworkPolicySpec.Egress + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []networkingv1.NetworkPolicyEgressRule, 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_NetworkPolicyEgressRule)...) + return + }(fldPath.Child("egress"), obj.Egress, safe.Field(oldObj, func(oldObj *networkingv1.NetworkPolicySpec) []networkingv1.NetworkPolicyEgressRule { + return oldObj.Egress + }), oldObj != nil)...) + + // field networkingv1.NetworkPolicySpec.PolicyTypes has no validation + return errs +} diff --git a/pkg/apis/networking/validation/validation.go b/pkg/apis/networking/validation/validation.go index 682e9ad8c85..893c6a98f2e 100644 --- a/pkg/apis/networking/validation/validation.go +++ b/pkg/apis/networking/validation/validation.go @@ -246,7 +246,7 @@ func ValidateNetworkPolicyUpdate(update, old *networking.NetworkPolicy, opts Net func ValidateIPBlock(ipb *networking.IPBlock, fldPath *field.Path, opts NetworkPolicyValidationOptions) field.ErrorList { allErrs := field.ErrorList{} if ipb.CIDR == "" { - allErrs = append(allErrs, field.Required(fldPath.Child("cidr"), "")) + allErrs = append(allErrs, field.Required(fldPath.Child("cidr"), "").MarkCoveredByDeclarative()) return allErrs } allErrs = append(allErrs, apivalidation.IsValidCIDRForLegacyField(fldPath.Child("cidr"), ipb.CIDR, opts.AllowCIDRsEvenIfInvalid)...) diff --git a/pkg/registry/networking/networkpolicy/declarative_validation_test.go b/pkg/registry/networking/networkpolicy/declarative_validation_test.go new file mode 100644 index 00000000000..cec89254982 --- /dev/null +++ b/pkg/registry/networking/networkpolicy/declarative_validation_test.go @@ -0,0 +1,214 @@ +/* +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 networkpolicy + +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"} + +func TestDeclarativeValidateIPBlockCIDR(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: "networkpolicies", + IsResourceRequest: true, + Verb: "create", + }, + ) + + testCases := map[string]struct { + input networking.NetworkPolicy + expectedErrs field.ErrorList + }{ + "valid ingress rule with CIDR": { + input: mkValidNetworkPolicy("ingress"), + }, + "valid egress rule with CIDR": { + input: mkValidNetworkPolicy("egress"), + }, + "ingress rule rejects empty CIDR in ipBlock": { + input: mkValidNetworkPolicy("ingress", tweakIngressFromIPBlock("")), + expectedErrs: field.ErrorList{ + field.Required( + field.NewPath("spec", "ingress").Index(0).Child("from").Index(0).Child("ipBlock", "cidr"), + "", + ), + }, + }, + "egress rule rejects empty CIDR in ipBlock": { + input: mkValidNetworkPolicy("egress", tweakEgressToIPBlock("")), + expectedErrs: field.ErrorList{ + field.Required( + field.NewPath("spec", "egress").Index(0).Child("to").Index(0).Child("ipBlock", "cidr"), + "", + ), + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + apitesting.VerifyValidationEquivalence( + t, + ctx, + &tc.input, + Strategy.Validate, + tc.expectedErrs, + ) + }) + } + }) + } +} + +func TestDeclarativeValidateIPBlockCIDRUpdate(t *testing.T) { + for _, apiVersion := range apiVersions { + t.Run(apiVersion, func(t *testing.T) { + testCases := map[string]struct { + oldObj networking.NetworkPolicy + updateObj networking.NetworkPolicy + expectedErrs field.ErrorList + }{ + "valid update ingress rule with CIDR": { + oldObj: mkValidNetworkPolicy("ingress"), + updateObj: mkValidNetworkPolicy("ingress", tweakIngressFromIPBlock("10.0.0.0/8")), + }, + "valid update egress rule with CIDR": { + oldObj: mkValidNetworkPolicy("egress"), + updateObj: mkValidNetworkPolicy("egress", tweakEgressToIPBlock("10.0.0.0/8")), + }, + "update ingress rule rejects empty CIDR in ipBlock": { + oldObj: mkValidNetworkPolicy("ingress"), + updateObj: mkValidNetworkPolicy("ingress", tweakIngressFromIPBlock("")), + expectedErrs: field.ErrorList{ + field.Required( + field.NewPath("spec", "ingress").Index(0).Child("from").Index(0).Child("ipBlock", "cidr"), + "", + ), + }, + }, + + "update egress rule rejects empty CIDR in ipBlock": { + oldObj: mkValidNetworkPolicy("egress"), + updateObj: mkValidNetworkPolicy("egress", tweakEgressToIPBlock("")), + expectedErrs: field.ErrorList{ + field.Required( + field.NewPath("spec", "egress").Index(0).Child("to").Index(0).Child("ipBlock", "cidr"), + "", + ), + }, + }, + } + + 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: "networkpolicies", + Name: "valid-network-policy", + IsResourceRequest: true, + Verb: "update", + }, + ) + + apitesting.VerifyUpdateValidationEquivalence( + t, + ctx, + &tc.updateObj, + &tc.oldObj, + Strategy.ValidateUpdate, + tc.expectedErrs, + ) + }) + } + }) + } +} + +func tweakIngressFromIPBlock(cidr string) func(obj *networking.NetworkPolicy) { + return func(obj *networking.NetworkPolicy) { + obj.Spec.Ingress[0].From[0].IPBlock.CIDR = cidr + } +} + +func tweakEgressToIPBlock(cidr string) func(obj *networking.NetworkPolicy) { + return func(obj *networking.NetworkPolicy) { + obj.Spec.Egress[0].To[0].IPBlock.CIDR = cidr + } +} +func mkValidNetworkPolicy(ruleType string, tweaks ...func(obj *networking.NetworkPolicy)) networking.NetworkPolicy { + obj := networking.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-network-policy", + Namespace: "default", + }, + Spec: networking.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{}, + }, + } + + switch ruleType { + case "ingress": + obj.Spec.Ingress = []networking.NetworkPolicyIngressRule{ + { + From: []networking.NetworkPolicyPeer{ + { + IPBlock: &networking.IPBlock{ + CIDR: "192.168.1.0/24", + }, + }, + }, + }, + } + case "egress": + obj.Spec.Egress = []networking.NetworkPolicyEgressRule{ + { + To: []networking.NetworkPolicyPeer{ + { + IPBlock: &networking.IPBlock{ + CIDR: "192.168.1.0/24", + }, + }, + }, + }, + } + } + + obj.ResourceVersion = "1" + + for _, tweak := range tweaks { + tweak(&obj) + } + return obj +} diff --git a/pkg/registry/networking/networkpolicy/strategy.go b/pkg/registry/networking/networkpolicy/strategy.go index 22b8deb144d..d2fb8c5902e 100644 --- a/pkg/registry/networking/networkpolicy/strategy.go +++ b/pkg/registry/networking/networkpolicy/strategy.go @@ -18,6 +18,8 @@ package networkpolicy import ( "context" + "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apiserver/pkg/registry/rest" "reflect" "k8s.io/apimachinery/pkg/runtime" @@ -66,7 +68,9 @@ func (networkPolicyStrategy) PrepareForUpdate(ctx context.Context, obj, old runt func (networkPolicyStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { networkPolicy := obj.(*networking.NetworkPolicy) ops := validation.ValidationOptionsForNetworking(networkPolicy, nil) - return validation.ValidateNetworkPolicy(networkPolicy, ops) + allErrs := validation.ValidateNetworkPolicy(networkPolicy, ops) + return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, networkPolicy, nil, allErrs, operation.Create) + } // WarningsOnCreate returns warnings for the creation of the given object. @@ -85,9 +89,8 @@ func (networkPolicyStrategy) AllowCreateOnUpdate() bool { // ValidateUpdate is the default update validation for an end user. func (networkPolicyStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { opts := validation.ValidationOptionsForNetworking(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy)) - validationErrorList := validation.ValidateNetworkPolicy(obj.(*networking.NetworkPolicy), opts) - updateErrorList := validation.ValidateNetworkPolicyUpdate(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy), opts) - return append(validationErrorList, updateErrorList...) + allErrs := validation.ValidateNetworkPolicyUpdate(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy), opts) + return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update) } // WarningsOnUpdate returns warnings for the given update. diff --git a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto index c664c71bd26..5d7415f1145 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto @@ -428,6 +428,8 @@ message HTTPIngressRuleValue { message IPBlock { // CIDR is a string representing the IP Block // Valid examples are "192.168.1.0/24" or "2001:db8::/64" + // +required + // +k8s:required optional string cidr = 1; // Except is a slice of CIDRs that should not be included within an IP Block @@ -746,6 +748,7 @@ message NetworkPolicyPeer { // IPBlock defines policy on a particular IPBlock. If this field is set then // neither of the other fields can be. // +optional + // +k8s:optional optional IPBlock ipBlock = 3; } diff --git a/staging/src/k8s.io/api/extensions/v1beta1/types.go b/staging/src/k8s.io/api/extensions/v1beta1/types.go index c0d8b4f9592..4d0f5a85a86 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/types.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/types.go @@ -1209,6 +1209,8 @@ type NetworkPolicyPort struct { type IPBlock struct { // CIDR is a string representing the IP Block // Valid examples are "192.168.1.0/24" or "2001:db8::/64" + // +required + // +k8s:required CIDR string `json:"cidr" protobuf:"bytes,1,name=cidr"` // Except is a slice of CIDRs that should not be included within an IP Block // Valid examples are "192.168.1.0/24" or "2001:db8::/64" @@ -1241,6 +1243,7 @@ type NetworkPolicyPeer struct { // IPBlock defines policy on a particular IPBlock. If this field is set then // neither of the other fields can be. // +optional + // +k8s:optional IPBlock *IPBlock `json:"ipBlock,omitempty" protobuf:"bytes,3,rep,name=ipBlock"` } diff --git a/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go b/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go index f4f0e317a76..a5c2187f07e 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go @@ -25,6 +25,7 @@ import ( context "context" fmt "fmt" + 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" @@ -37,6 +38,14 @@ 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 NetworkPolicy + scheme.AddValidationFunc((*NetworkPolicy)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_NetworkPolicy(ctx, op, nil /* fldPath */, obj.(*NetworkPolicy), safe.Cast[*NetworkPolicy](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) // type Scale scheme.AddValidationFunc((*Scale)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { switch op.Request.SubresourcePath() { @@ -48,6 +57,155 @@ func RegisterValidations(scheme *runtime.Scheme) error { return nil } +// Validate_IPBlock validates an instance of IPBlock according +// to declarative validation rules in the API schema. +func Validate_IPBlock(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *IPBlock) (errs field.ErrorList) { + // field IPBlock.CIDR + 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("cidr"), &obj.CIDR, safe.Field(oldObj, func(oldObj *IPBlock) *string { return &oldObj.CIDR }), oldObj != nil)...) + + // field IPBlock.Except has no validation + return errs +} + +// Validate_NetworkPolicy validates an instance of NetworkPolicy according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicy(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *NetworkPolicy) (errs field.ErrorList) { + // field NetworkPolicy.TypeMeta has no validation + // field NetworkPolicy.ObjectMeta has no validation + + // field NetworkPolicy.Spec + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *NetworkPolicySpec, 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_NetworkPolicySpec(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("spec"), &obj.Spec, safe.Field(oldObj, func(oldObj *NetworkPolicy) *NetworkPolicySpec { return &oldObj.Spec }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyEgressRule validates an instance of NetworkPolicyEgressRule according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyEgressRule(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *NetworkPolicyEgressRule) (errs field.ErrorList) { + // field NetworkPolicyEgressRule.Ports has no validation + + // field NetworkPolicyEgressRule.To + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []NetworkPolicyPeer, 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_NetworkPolicyPeer)...) + return + }(fldPath.Child("to"), obj.To, safe.Field(oldObj, func(oldObj *NetworkPolicyEgressRule) []NetworkPolicyPeer { return oldObj.To }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyIngressRule validates an instance of NetworkPolicyIngressRule according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyIngressRule(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *NetworkPolicyIngressRule) (errs field.ErrorList) { + // field NetworkPolicyIngressRule.Ports has no validation + + // field NetworkPolicyIngressRule.From + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []NetworkPolicyPeer, 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_NetworkPolicyPeer)...) + return + }(fldPath.Child("from"), obj.From, safe.Field(oldObj, func(oldObj *NetworkPolicyIngressRule) []NetworkPolicyPeer { return oldObj.From }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicyPeer validates an instance of NetworkPolicyPeer according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicyPeer(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *NetworkPolicyPeer) (errs field.ErrorList) { + // field NetworkPolicyPeer.PodSelector has no validation + // field NetworkPolicyPeer.NamespaceSelector has no validation + + // field NetworkPolicyPeer.IPBlock + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *IPBlock, 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_IPBlock(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("ipBlock"), obj.IPBlock, safe.Field(oldObj, func(oldObj *NetworkPolicyPeer) *IPBlock { return oldObj.IPBlock }), oldObj != nil)...) + + return errs +} + +// Validate_NetworkPolicySpec validates an instance of NetworkPolicySpec according +// to declarative validation rules in the API schema. +func Validate_NetworkPolicySpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *NetworkPolicySpec) (errs field.ErrorList) { + // field NetworkPolicySpec.PodSelector has no validation + + // field NetworkPolicySpec.Ingress + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []NetworkPolicyIngressRule, 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_NetworkPolicyIngressRule)...) + return + }(fldPath.Child("ingress"), obj.Ingress, safe.Field(oldObj, func(oldObj *NetworkPolicySpec) []NetworkPolicyIngressRule { return oldObj.Ingress }), oldObj != nil)...) + + // field NetworkPolicySpec.Egress + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []NetworkPolicyEgressRule, 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_NetworkPolicyEgressRule)...) + return + }(fldPath.Child("egress"), obj.Egress, safe.Field(oldObj, func(oldObj *NetworkPolicySpec) []NetworkPolicyEgressRule { return oldObj.Egress }), oldObj != nil)...) + + // field NetworkPolicySpec.PolicyTypes has no validation + return errs +} + // Validate_Scale validates an instance of Scale according // to declarative validation rules in the API schema. func Validate_Scale(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Scale) (errs field.ErrorList) { diff --git a/staging/src/k8s.io/api/networking/v1/generated.proto b/staging/src/k8s.io/api/networking/v1/generated.proto index 2231eda22ad..c5d0c8c9c11 100644 --- a/staging/src/k8s.io/api/networking/v1/generated.proto +++ b/staging/src/k8s.io/api/networking/v1/generated.proto @@ -116,6 +116,8 @@ message IPAddressSpec { message IPBlock { // cidr is a string representing the IPBlock // Valid examples are "192.168.1.0/24" or "2001:db8::/64" + // +required + // +k8s:required optional string cidr = 1; // except is a slice of CIDRs that should not be included within an IPBlock @@ -511,6 +513,7 @@ message NetworkPolicyPeer { // ipBlock defines policy on a particular IPBlock. If this field is set then // neither of the other fields can be. // +optional + // +k8s:optional optional IPBlock ipBlock = 3; } diff --git a/staging/src/k8s.io/api/networking/v1/types.go b/staging/src/k8s.io/api/networking/v1/types.go index 0188ee0fd5b..c239d7df506 100644 --- a/staging/src/k8s.io/api/networking/v1/types.go +++ b/staging/src/k8s.io/api/networking/v1/types.go @@ -178,6 +178,8 @@ type NetworkPolicyPort struct { type IPBlock struct { // cidr is a string representing the IPBlock // Valid examples are "192.168.1.0/24" or "2001:db8::/64" + // +required + // +k8s:required CIDR string `json:"cidr" protobuf:"bytes,1,name=cidr"` // except is a slice of CIDRs that should not be included within an IPBlock @@ -212,6 +214,7 @@ type NetworkPolicyPeer struct { // ipBlock defines policy on a particular IPBlock. If this field is set then // neither of the other fields can be. // +optional + // +k8s:optional IPBlock *IPBlock `json:"ipBlock,omitempty" protobuf:"bytes,3,rep,name=ipBlock"` }