From 5ee4b49ebd79b4fdef802c7e92af5b5cab6cdb9b Mon Sep 17 00:00:00 2001 From: CLBRITTON2 Date: Fri, 9 Jan 2026 08:36:47 -0500 Subject: [PATCH] Add declarative validation tests for EndpointSlice addressType immutability --- pkg/apis/discovery/v1/zz_generated.validations.go | 4 ++++ pkg/apis/discovery/v1beta1/zz_generated.validations.go | 4 ++++ pkg/apis/discovery/validation/validation.go | 2 +- .../discovery/endpointslice/declarative_validation_test.go | 7 +++++++ staging/src/k8s.io/api/discovery/v1/generated.proto | 1 + staging/src/k8s.io/api/discovery/v1/types.go | 1 + staging/src/k8s.io/api/discovery/v1beta1/generated.proto | 1 + staging/src/k8s.io/api/discovery/v1beta1/types.go | 1 + 8 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pkg/apis/discovery/v1/zz_generated.validations.go b/pkg/apis/discovery/v1/zz_generated.validations.go index 2766f592446..e5fed4b47f8 100644 --- a/pkg/apis/discovery/v1/zz_generated.validations.go +++ b/pkg/apis/discovery/v1/zz_generated.validations.go @@ -101,6 +101,10 @@ func Validate_EndpointSlice(ctx context.Context, op operation.Operation, fldPath } // 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 e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) earlyReturn = true diff --git a/pkg/apis/discovery/v1beta1/zz_generated.validations.go b/pkg/apis/discovery/v1beta1/zz_generated.validations.go index ba337446aa7..c41ef7de08b 100644 --- a/pkg/apis/discovery/v1beta1/zz_generated.validations.go +++ b/pkg/apis/discovery/v1beta1/zz_generated.validations.go @@ -100,6 +100,10 @@ func Validate_EndpointSlice(ctx context.Context, op operation.Operation, fldPath } // 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 e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) earlyReturn = true diff --git a/pkg/apis/discovery/validation/validation.go b/pkg/apis/discovery/validation/validation.go index be93d297206..89a6b584dfd 100644 --- a/pkg/apis/discovery/validation/validation.go +++ b/pkg/apis/discovery/validation/validation.go @@ -86,7 +86,7 @@ func ValidateEndpointSliceCreate(endpointSlice *discovery.EndpointSlice) field.E // ValidateEndpointSliceUpdate validates an EndpointSlice when it is updated. func ValidateEndpointSliceUpdate(newEndpointSlice, oldEndpointSlice *discovery.EndpointSlice) field.ErrorList { allErrs := ValidateEndpointSlice(newEndpointSlice, oldEndpointSlice) - allErrs = append(allErrs, apivalidation.ValidateImmutableField(newEndpointSlice.AddressType, oldEndpointSlice.AddressType, field.NewPath("addressType"))...) + allErrs = append(allErrs, apivalidation.ValidateImmutableField(newEndpointSlice.AddressType, oldEndpointSlice.AddressType, field.NewPath("addressType")).WithOrigin("immutable").MarkCoveredByDeclarative()...) return allErrs } diff --git a/pkg/registry/discovery/endpointslice/declarative_validation_test.go b/pkg/registry/discovery/endpointslice/declarative_validation_test.go index 9c78e9caa06..496a4b042ae 100644 --- a/pkg/registry/discovery/endpointslice/declarative_validation_test.go +++ b/pkg/registry/discovery/endpointslice/declarative_validation_test.go @@ -122,6 +122,13 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { field.TooMany(field.NewPath("endpoints").Index(0).Child("addresses"), 101, 100).WithOrigin("maxItems"), }, }, + "invalid update addressType immutable": { + oldObj: mkValidEndpointSlice(), + updateObj: mkValidEndpointSlice(tweakAddressType(discovery.AddressTypeIPv6)), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("addressType"), discovery.AddressTypeIPv6, "field is immutable").WithOrigin("immutable"), + }, + }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { diff --git a/staging/src/k8s.io/api/discovery/v1/generated.proto b/staging/src/k8s.io/api/discovery/v1/generated.proto index 146865d8fc0..d8bbf2d4ab7 100644 --- a/staging/src/k8s.io/api/discovery/v1/generated.proto +++ b/staging/src/k8s.io/api/discovery/v1/generated.proto @@ -186,6 +186,7 @@ message EndpointSlice { // the "FQDN" type. // +required // +k8s:required + // +k8s:immutable optional string addressType = 4; // endpoints is a list of unique endpoints in this slice. Each slice may diff --git a/staging/src/k8s.io/api/discovery/v1/types.go b/staging/src/k8s.io/api/discovery/v1/types.go index a682a4596df..de83652ac0c 100644 --- a/staging/src/k8s.io/api/discovery/v1/types.go +++ b/staging/src/k8s.io/api/discovery/v1/types.go @@ -50,6 +50,7 @@ type EndpointSlice struct { // the "FQDN" type. // +required // +k8s:required + // +k8s:immutable AddressType AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"` // endpoints is a list of unique endpoints in this slice. Each slice may diff --git a/staging/src/k8s.io/api/discovery/v1beta1/generated.proto b/staging/src/k8s.io/api/discovery/v1beta1/generated.proto index 2be880149e1..d540d2ea06f 100644 --- a/staging/src/k8s.io/api/discovery/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/discovery/v1beta1/generated.proto @@ -172,6 +172,7 @@ message EndpointSlice { // * FQDN: Represents a Fully Qualified Domain Name. // +required // +k8s:required + // +k8s:immutable optional string addressType = 4; // endpoints is a list of unique endpoints in this slice. Each slice may diff --git a/staging/src/k8s.io/api/discovery/v1beta1/types.go b/staging/src/k8s.io/api/discovery/v1beta1/types.go index fbc65ab5fdf..a04d98d01c1 100644 --- a/staging/src/k8s.io/api/discovery/v1beta1/types.go +++ b/staging/src/k8s.io/api/discovery/v1beta1/types.go @@ -47,6 +47,7 @@ type EndpointSlice struct { // * FQDN: Represents a Fully Qualified Domain Name. // +required // +k8s:required + // +k8s:immutable AddressType AddressType `json:"addressType" protobuf:"bytes,4,rep,name=addressType"` // endpoints is a list of unique endpoints in this slice. Each slice may