From b13564a63c36c9d5f0a8ef7ab6467dc3a9fa0017 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 4 Oct 2025 08:31:57 -0400 Subject: [PATCH 1/5] Belatedly remove references to PreferSameTrafficDistribution being Alpha --- api/openapi-spec/swagger.json | 2 +- api/openapi-spec/v3/apis__discovery.k8s.io__v1_openapi.json | 2 +- pkg/apis/core/types.go | 5 +---- pkg/apis/discovery/types.go | 4 +--- pkg/generated/openapi/zz_generated.openapi.go | 4 ++-- staging/src/k8s.io/api/core/v1/types.go | 5 +---- staging/src/k8s.io/api/discovery/v1/generated.proto | 2 -- staging/src/k8s.io/api/discovery/v1/types.go | 2 -- .../k8s.io/api/discovery/v1/types_swagger_doc_generated.go | 2 +- staging/src/k8s.io/api/discovery/v1beta1/generated.proto | 2 -- staging/src/k8s.io/api/discovery/v1beta1/types.go | 2 -- .../api/discovery/v1beta1/types_swagger_doc_generated.go | 2 +- .../applyconfigurations/discovery/v1/endpointhints.go | 2 -- .../applyconfigurations/discovery/v1beta1/endpointhints.go | 2 -- 14 files changed, 9 insertions(+), 29 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 28043b8fedf..98a5a29165a 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -12639,7 +12639,7 @@ "description": "EndpointHints provides hints describing how an endpoint should be consumed.", "properties": { "forNodes": { - "description": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + "description": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", "items": { "$ref": "#/definitions/io.k8s.api.discovery.v1.ForNode" }, diff --git a/api/openapi-spec/v3/apis__discovery.k8s.io__v1_openapi.json b/api/openapi-spec/v3/apis__discovery.k8s.io__v1_openapi.json index 10ff32b23e4..4babe114776 100644 --- a/api/openapi-spec/v3/apis__discovery.k8s.io__v1_openapi.json +++ b/api/openapi-spec/v3/apis__discovery.k8s.io__v1_openapi.json @@ -121,7 +121,7 @@ "description": "EndpointHints provides hints describing how an endpoint should be consumed.", "properties": { "forNodes": { - "description": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + "description": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", "items": { "allOf": [ { diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index 24448a8dd58..b6a91b1dd92 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -4848,16 +4848,13 @@ const ( // zone as the client. Users should not set this value unless they have ensured // that clients and endpoints are distributed in such a way that the "same zone" // preference will not result in endpoints getting overloaded. - // This is an alias for "PreferClose", but it is an Alpha feature and is only - // recognized if the PreferSameTrafficDistribution feature gate is enabled. + // This is an alias for "PreferClose". ServiceTrafficDistributionPreferSameZone = "PreferSameZone" // Indicates a preference for routing traffic to endpoints that are on the same // node as the client. Users should not set this value unless they have ensured // that clients and endpoints are distributed in such a way that the "same node" // preference will not result in endpoints getting overloaded. - // This is an Alpha feature and is only recognized if the - // PreferSameTrafficDistribution feature gate is enabled. ServiceTrafficDistributionPreferSameNode = "PreferSameNode" ) diff --git a/pkg/apis/discovery/types.go b/pkg/apis/discovery/types.go index c31c8f19ee8..f227511833a 100644 --- a/pkg/apis/discovery/types.go +++ b/pkg/apis/discovery/types.go @@ -138,9 +138,7 @@ type EndpointHints struct { ForZones []ForZone // forNodes indicates the node(s) this endpoint should be consumed by when - // using topology aware routing. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. May contain a maximum of 8 entries. + // using topology aware routing. May contain a maximum of 8 entries. // +featureGate=PreferSameTrafficDistribution ForNodes []ForNode } diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index d1acfb695e2..52939e9b4ed 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -34820,7 +34820,7 @@ func schema_k8sio_api_discovery_v1_EndpointHints(ref common.ReferenceCallback) c }, }, SchemaProps: spec.SchemaProps{ - Description: "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + Description: "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -35218,7 +35218,7 @@ func schema_k8sio_api_discovery_v1beta1_EndpointHints(ref common.ReferenceCallba }, }, SchemaProps: spec.SchemaProps{ - Description: "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + Description: "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index cc992af4e08..40ab5169b92 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -5716,16 +5716,13 @@ const ( // zone as the client. Users should not set this value unless they have ensured // that clients and endpoints are distributed in such a way that the "same zone" // preference will not result in endpoints getting overloaded. - // This is an alias for "PreferClose", but it is an Alpha feature and is only - // recognized if the PreferSameTrafficDistribution feature gate is enabled. + // This is an alias for "PreferClose". ServiceTrafficDistributionPreferSameZone = "PreferSameZone" // Indicates a preference for routing traffic to endpoints that are on the same // node as the client. Users should not set this value unless they have ensured // that clients and endpoints are distributed in such a way that the "same node" // preference will not result in endpoints getting overloaded. - // This is an Alpha feature and is only recognized if the - // PreferSameTrafficDistribution feature gate is enabled. ServiceTrafficDistributionPreferSameNode = "PreferSameNode" ) diff --git a/staging/src/k8s.io/api/discovery/v1/generated.proto b/staging/src/k8s.io/api/discovery/v1/generated.proto index 569d8a916ef..97582a1b2a0 100644 --- a/staging/src/k8s.io/api/discovery/v1/generated.proto +++ b/staging/src/k8s.io/api/discovery/v1/generated.proto @@ -114,8 +114,6 @@ message EndpointHints { // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. // +listType=atomic repeated ForNode forNodes = 2; } diff --git a/staging/src/k8s.io/api/discovery/v1/types.go b/staging/src/k8s.io/api/discovery/v1/types.go index 6f26953169c..ca78ce38696 100644 --- a/staging/src/k8s.io/api/discovery/v1/types.go +++ b/staging/src/k8s.io/api/discovery/v1/types.go @@ -166,8 +166,6 @@ type EndpointHints struct { // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. // +listType=atomic ForNodes []ForNode `json:"forNodes,omitempty" protobuf:"bytes,2,name=forNodes"` } diff --git a/staging/src/k8s.io/api/discovery/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/discovery/v1/types_swagger_doc_generated.go index ac5b853b9e1..ba8b0363ada 100644 --- a/staging/src/k8s.io/api/discovery/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/discovery/v1/types_swagger_doc_generated.go @@ -57,7 +57,7 @@ func (EndpointConditions) SwaggerDoc() map[string]string { var map_EndpointHints = map[string]string{ "": "EndpointHints provides hints describing how an endpoint should be consumed.", "forZones": "forZones indicates the zone(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", - "forNodes": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + "forNodes": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", } func (EndpointHints) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/discovery/v1beta1/generated.proto b/staging/src/k8s.io/api/discovery/v1beta1/generated.proto index 907050da1c5..7b9d983b831 100644 --- a/staging/src/k8s.io/api/discovery/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/discovery/v1beta1/generated.proto @@ -117,8 +117,6 @@ message EndpointHints { // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. // +listType=atomic repeated ForNode forNodes = 2; } diff --git a/staging/src/k8s.io/api/discovery/v1beta1/types.go b/staging/src/k8s.io/api/discovery/v1beta1/types.go index fa9d1eae43b..11ec1b3968a 100644 --- a/staging/src/k8s.io/api/discovery/v1beta1/types.go +++ b/staging/src/k8s.io/api/discovery/v1beta1/types.go @@ -164,8 +164,6 @@ type EndpointHints struct { // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. // +listType=atomic ForNodes []ForNode `json:"forNodes,omitempty" protobuf:"bytes,2,name=forNodes"` } diff --git a/staging/src/k8s.io/api/discovery/v1beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/discovery/v1beta1/types_swagger_doc_generated.go index 72aa0cb9b22..acc83837847 100644 --- a/staging/src/k8s.io/api/discovery/v1beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/discovery/v1beta1/types_swagger_doc_generated.go @@ -56,7 +56,7 @@ func (EndpointConditions) SwaggerDoc() map[string]string { var map_EndpointHints = map[string]string{ "": "EndpointHints provides hints describing how an endpoint should be consumed.", "forZones": "forZones indicates the zone(s) this endpoint should be consumed by to enable topology aware routing. May contain a maximum of 8 entries.", - "forNodes": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries. This is an Alpha feature and is only used when the PreferSameTrafficDistribution feature gate is enabled.", + "forNodes": "forNodes indicates the node(s) this endpoint should be consumed by when using topology aware routing. May contain a maximum of 8 entries.", } func (EndpointHints) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1/endpointhints.go b/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1/endpointhints.go index f405d19dd0c..7b9e5be752e 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1/endpointhints.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1/endpointhints.go @@ -28,8 +28,6 @@ type EndpointHintsApplyConfiguration struct { ForZones []ForZoneApplyConfiguration `json:"forZones,omitempty"` // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. ForNodes []ForNodeApplyConfiguration `json:"forNodes,omitempty"` } diff --git a/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1beta1/endpointhints.go b/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1beta1/endpointhints.go index 70386faab6e..0e36451a7f7 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1beta1/endpointhints.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/discovery/v1beta1/endpointhints.go @@ -28,8 +28,6 @@ type EndpointHintsApplyConfiguration struct { ForZones []ForZoneApplyConfiguration `json:"forZones,omitempty"` // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // This is an Alpha feature and is only used when the PreferSameTrafficDistribution - // feature gate is enabled. ForNodes []ForNodeApplyConfiguration `json:"forNodes,omitempty"` } From 02926c9563d2f05627e9831a7d9eba3cd01fcf71 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 4 Oct 2025 08:28:57 -0400 Subject: [PATCH 2/5] Update PreferSameTrafficDistribution to GA --- pkg/apis/core/validation/validation_test.go | 3 +++ pkg/apis/discovery/types.go | 1 - pkg/features/kube_features.go | 1 + pkg/proxy/topology_test.go | 4 ++++ pkg/registry/discovery/endpointslice/strategy_test.go | 11 +++++++---- .../reference/versioned_feature_list.yaml | 4 ++++ test/e2e/network/traffic_distribution.go | 9 ++++----- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index e0268c2123d..fbea795fa5f 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -17569,6 +17569,9 @@ func TestValidateServiceCreate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + if !tc.newTrafficDist { + featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.34")) + } featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{ features.PreferSameTrafficDistribution: tc.newTrafficDist, features.RelaxedServiceNameValidation: tc.relaxedServiceNames, diff --git a/pkg/apis/discovery/types.go b/pkg/apis/discovery/types.go index f227511833a..de78ceeed28 100644 --- a/pkg/apis/discovery/types.go +++ b/pkg/apis/discovery/types.go @@ -139,7 +139,6 @@ type EndpointHints struct { // forNodes indicates the node(s) this endpoint should be consumed by when // using topology aware routing. May contain a maximum of 8 entries. - // +featureGate=PreferSameTrafficDistribution ForNodes []ForNode } diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 8cc208a2799..828db25d38e 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -1524,6 +1524,7 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate PreferSameTrafficDistribution: { {Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Alpha}, {Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.Beta}, + {Version: version.MustParse("1.35"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, }, PreventStaticPodAPIReferences: { diff --git a/pkg/proxy/topology_test.go b/pkg/proxy/topology_test.go index ad523c23306..8e9ed4333d2 100644 --- a/pkg/proxy/topology_test.go +++ b/pkg/proxy/topology_test.go @@ -23,6 +23,7 @@ import ( v1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/version" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/features" @@ -401,6 +402,9 @@ func TestCategorizeEndpoints(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + if !tc.preferSameEnabled { + featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.34")) + } featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PreferSameTrafficDistribution, tc.preferSameEnabled) clusterEndpoints, localEndpoints, allEndpoints, hasAnyEndpoints := CategorizeEndpoints(tc.endpoints, tc.serviceInfo, tc.nodeName, tc.nodeLabels) diff --git a/pkg/registry/discovery/endpointslice/strategy_test.go b/pkg/registry/discovery/endpointslice/strategy_test.go index 3113fc3242d..ad8e2bfcd8a 100644 --- a/pkg/registry/discovery/endpointslice/strategy_test.go +++ b/pkg/registry/discovery/endpointslice/strategy_test.go @@ -115,7 +115,10 @@ func Test_dropDisabledFieldsOnCreate(t *testing.T) { for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { - featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PreferSameTrafficDistribution, testcase.preferSameEnabled) + if !testcase.preferSameEnabled { + featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.34")) + featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PreferSameTrafficDistribution, false) + } dropDisabledFieldsOnCreate(testcase.eps) if !apiequality.Semantic.DeepEqual(testcase.eps, testcase.expectedEPS) { @@ -413,9 +416,9 @@ func Test_dropDisabledFieldsOnUpdate(t *testing.T) { t.Run(testcase.name, func(t *testing.T) { if !testcase.hintsGateEnabled { featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.32")) - } - featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled) - if testcase.hintsGateEnabled { + featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled) + } else if !testcase.preferSameEnabled { + featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.34")) featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PreferSameTrafficDistribution, testcase.preferSameEnabled) } diff --git a/test/compatibility_lifecycle/reference/versioned_feature_list.yaml b/test/compatibility_lifecycle/reference/versioned_feature_list.yaml index 6b20d66d559..ef386bcf930 100644 --- a/test/compatibility_lifecycle/reference/versioned_feature_list.yaml +++ b/test/compatibility_lifecycle/reference/versioned_feature_list.yaml @@ -1227,6 +1227,10 @@ lockToDefault: false preRelease: Beta version: "1.34" + - default: true + lockToDefault: true + preRelease: GA + version: "1.35" - name: PreventStaticPodAPIReferences versionedSpecs: - default: true diff --git a/test/e2e/network/traffic_distribution.go b/test/e2e/network/traffic_distribution.go index 1e5fa3d4d9a..28892ebe02c 100644 --- a/test/e2e/network/traffic_distribution.go +++ b/test/e2e/network/traffic_distribution.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" clientset "k8s.io/client-go/kubernetes" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/test/e2e/framework" e2eendpointslice "k8s.io/kubernetes/test/e2e/framework/endpointslice" e2enode "k8s.io/kubernetes/test/e2e/framework/node" @@ -362,21 +361,21 @@ var _ = common.SIGDescribe("Traffic Distribution", func() { checkTrafficDistribution(ctx, clientPods) }) - framework.It("should route traffic to an endpoint in the same zone when using PreferSameZone", framework.WithFeatureGate(features.PreferSameTrafficDistribution), func(ctx context.Context) { + framework.It("should route traffic to an endpoint in the same zone when using PreferSameZone", func(ctx context.Context) { clientPods, serverPods := allocateClientsAndServers(ctx) svc := createService(ctx, v1.ServiceTrafficDistributionPreferSameZone) createPods(ctx, svc, clientPods, serverPods) checkTrafficDistribution(ctx, clientPods) }) - framework.It("should route traffic correctly between pods on multiple nodes when using PreferSameZone", framework.WithFeatureGate(features.PreferSameTrafficDistribution), func(ctx context.Context) { + framework.It("should route traffic correctly between pods on multiple nodes when using PreferSameZone", func(ctx context.Context) { clientPods, serverPods := allocateMultiNodeClientsAndServers(ctx) svc := createService(ctx, v1.ServiceTrafficDistributionPreferSameZone) createPods(ctx, svc, clientPods, serverPods) checkTrafficDistribution(ctx, clientPods) }) - framework.It("should route traffic to an endpoint on the same node or fall back to same zone when using PreferSameNode", framework.WithFeatureGate(features.PreferSameTrafficDistribution), func(ctx context.Context) { + framework.It("should route traffic to an endpoint on the same node or fall back to same zone when using PreferSameNode", func(ctx context.Context) { ginkgo.By("finding a set of nodes for the test") zone1Nodes, zone2Nodes, zone3Nodes := getNodesForMultiNode(ctx) @@ -428,7 +427,7 @@ var _ = common.SIGDescribe("Traffic Distribution", func() { checkTrafficDistribution(ctx, clientPods) }) - framework.It("should route traffic to an endpoint on the same node when using PreferSameNode and fall back when the endpoint becomes unavailable", framework.WithFeatureGate(features.PreferSameTrafficDistribution), func(ctx context.Context) { + framework.It("should route traffic to an endpoint on the same node when using PreferSameNode and fall back when the endpoint becomes unavailable", func(ctx context.Context) { ginkgo.By("finding a set of nodes for the test") nodeList, err := e2enode.GetReadySchedulableNodes(ctx, c) framework.ExpectNoError(err) From c6a86d125f2dc5a871b1a11c6ccc7da88b170b40 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 4 Oct 2025 08:42:40 -0400 Subject: [PATCH 3/5] Merge the two TrafficDistribution integration tests --- test/integration/service/service_test.go | 139 +---------------------- 1 file changed, 1 insertion(+), 138 deletions(-) diff --git a/test/integration/service/service_test.go b/test/integration/service/service_test.go index 3d50f8d4a7e..296f5532b42 100644 --- a/test/integration/service/service_test.go +++ b/test/integration/service/service_test.go @@ -549,143 +549,6 @@ func Test_TransitionsForTrafficDistribution(t *testing.T) { } assertEndpointSliceHints(t, ctx, client, ns.GetName(), svc.GetName(), false, false) -} - -// Test transitions involving the `trafficDistribution` field with -// PreferSameTrafficDistribution enabled. -func Test_TransitionsForPreferSameTrafficDistribution(t *testing.T) { - - //////////////////////////////////////////////////////////////////////////// - // Setup components, like kube-apiserver and EndpointSlice controller. - //////////////////////////////////////////////////////////////////////////// - - featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{ - features.ServiceTrafficDistribution: true, - features.PreferSameTrafficDistribution: true, - }) - - // Disable ServiceAccount admission plugin as we don't have serviceaccount controller running. - server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd()) - defer server.TearDownFn() - - client, err := clientset.NewForConfig(server.ClientConfig) - if err != nil { - t.Fatalf("Error creating clientset: %v", err) - } - - resyncPeriod := 12 * time.Hour - informers := informers.NewSharedInformerFactory(client, resyncPeriod) - - ctx := ktesting.Init(t) - defer ctx.Cancel("test has completed") - epsController := endpointslice.NewController( - ctx, - informers.Core().V1().Pods(), - informers.Core().V1().Services(), - informers.Core().V1().Nodes(), - informers.Discovery().V1().EndpointSlices(), - int32(100), - client, - 1*time.Second, - ) - - informers.Start(ctx.Done()) - go epsController.Run(ctx, 1) - - //////////////////////////////////////////////////////////////////////////// - // Create a namespace, node, pod in the node, and a service exposing the pod. - //////////////////////////////////////////////////////////////////////////// - - ns := framework.CreateNamespaceOrDie(client, "test-service-traffic-distribution", t) - defer framework.DeleteNamespaceOrDie(client, ns, t) - - node := &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "fake-node", - Labels: map[string]string{ - corev1.LabelTopologyZone: "fake-zone-1", - }, - }, - } - - pod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: ns.GetName(), - Labels: map[string]string{ - "foo": "bar", - }, - }, - Spec: corev1.PodSpec{ - NodeName: node.GetName(), - Containers: []corev1.Container{ - { - Name: "fake-name", - Image: "fake-image", - Ports: []corev1.ContainerPort{ - { - Name: "port-443", - ContainerPort: 443, - }, - }, - }, - }, - }, - Status: corev1.PodStatus{ - Phase: corev1.PodRunning, - Conditions: []corev1.PodCondition{ - { - Type: corev1.PodReady, - Status: corev1.ConditionTrue, - }, - }, - PodIP: "10.0.0.1", - PodIPs: []corev1.PodIP{ - { - IP: "10.0.0.1", - }, - }, - }, - } - - svc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-service", - Namespace: ns.GetName(), - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "foo": "bar", - }, - Ports: []corev1.ServicePort{ - {Name: "port-443", Port: 443, Protocol: "TCP", TargetPort: intstr.FromInt32(443)}, - }, - }, - } - - _, err = client.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{}) - if err != nil { - t.Fatalf("Failed to create test node: %v", err) - } - _, err = client.CoreV1().Pods(ns.Name).Create(ctx, pod, metav1.CreateOptions{}) - if err != nil { - t.Fatalf("Failed to create test ready pod: %v", err) - } - _, err = client.CoreV1().Pods(ns.Name).UpdateStatus(ctx, pod, metav1.UpdateOptions{}) - if err != nil { - t.Fatalf("Failed to update status for test pod to Ready: %v", err) - } - _, err = client.CoreV1().Services(ns.Name).Create(ctx, svc, metav1.CreateOptions{}) - if err != nil { - t.Fatalf("Failed to create test service: %v", err) - } - - //////////////////////////////////////////////////////////////////////////// - // Assert that without the presence of `trafficDistribution` field there are - // no zone hints in EndpointSlice. - //////////////////////////////////////////////////////////////////////////// - - assertEndpointSliceHints(t, ctx, client, ns.GetName(), svc.GetName(), false, false) //////////////////////////////////////////////////////////////////////////// // Update the service by setting `trafficDistribution: PreferSameZone` @@ -693,7 +556,7 @@ func Test_TransitionsForPreferSameTrafficDistribution(t *testing.T) { // Assert that the respective EndpointSlices get the same-zone hints. //////////////////////////////////////////////////////////////////////////// - trafficDist := corev1.ServiceTrafficDistributionPreferSameZone + trafficDist = corev1.ServiceTrafficDistributionPreferSameZone svc.Spec.TrafficDistribution = &trafficDist _, err = client.CoreV1().Services(ns.Name).Update(ctx, svc, metav1.UpdateOptions{}) if err != nil { From 3176ef27602bc173182cbab3539c085d0649f0bb Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 4 Oct 2025 08:32:29 -0400 Subject: [PATCH 4/5] Update TrafficDistribution docs for PreferSame* GA --- pkg/apis/core/types.go | 31 +++++++++++++------------ staging/src/k8s.io/api/core/v1/types.go | 31 +++++++++++++------------ 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index b6a91b1dd92..4949c7a5aa5 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -4838,24 +4838,25 @@ const ( // These are valid values for the TrafficDistribution field of a Service. const ( - // Indicates a preference for routing traffic to endpoints that are in the same - // zone as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same zone" - // preference will not result in endpoints getting overloaded. - ServiceTrafficDistributionPreferClose = "PreferClose" - - // Indicates a preference for routing traffic to endpoints that are in the same - // zone as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same zone" - // preference will not result in endpoints getting overloaded. - // This is an alias for "PreferClose". + // ServiceTrafficDistributionPreferSameZone indicates a preference for routing + // traffic to endpoints that are in the same zone as the client. Users should only + // set this value if they have ensured that clients and endpoints are distributed + // in such a way that the "same zone" preference will not result in endpoints + // getting overloaded. ServiceTrafficDistributionPreferSameZone = "PreferSameZone" - // Indicates a preference for routing traffic to endpoints that are on the same - // node as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same node" - // preference will not result in endpoints getting overloaded. + // ServiceTrafficDistributionPreferSameNode indicates a preference for routing + // traffic to endpoints that are on the same node as the client. Users should only + // set this value if they have ensured that clients and endpoints are distributed + // in such a way that the "same node" preference will not result in endpoints + // getting overloaded. ServiceTrafficDistributionPreferSameNode = "PreferSameNode" + + // ServiceTrafficDistributionPreferClose is the original name of "PreferSameZone". + // Despite the generic-sounding name, it has exactly the same meaning as + // "PreferSameZone". + // Deprecated: use "PreferSameZone" instead. + ServiceTrafficDistributionPreferClose = "PreferClose" ) // These are the valid conditions of a service. diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index 40ab5169b92..968b6a0147b 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -5706,24 +5706,25 @@ const ( // These are valid values for the TrafficDistribution field of a Service. const ( - // Indicates a preference for routing traffic to endpoints that are in the same - // zone as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same zone" - // preference will not result in endpoints getting overloaded. - ServiceTrafficDistributionPreferClose = "PreferClose" - - // Indicates a preference for routing traffic to endpoints that are in the same - // zone as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same zone" - // preference will not result in endpoints getting overloaded. - // This is an alias for "PreferClose". + // ServiceTrafficDistributionPreferSameZone indicates a preference for routing + // traffic to endpoints that are in the same zone as the client. Users should only + // set this value if they have ensured that clients and endpoints are distributed + // in such a way that the "same zone" preference will not result in endpoints + // getting overloaded. ServiceTrafficDistributionPreferSameZone = "PreferSameZone" - // Indicates a preference for routing traffic to endpoints that are on the same - // node as the client. Users should not set this value unless they have ensured - // that clients and endpoints are distributed in such a way that the "same node" - // preference will not result in endpoints getting overloaded. + // ServiceTrafficDistributionPreferSameNode indicates a preference for routing + // traffic to endpoints that are on the same node as the client. Users should only + // set this value if they have ensured that clients and endpoints are distributed + // in such a way that the "same node" preference will not result in endpoints + // getting overloaded. ServiceTrafficDistributionPreferSameNode = "PreferSameNode" + + // ServiceTrafficDistributionPreferClose is the original name of "PreferSameZone". + // Despite the generic-sounding name, it has exactly the same meaning as + // "PreferSameZone". + // Deprecated: use "PreferSameZone" instead. + ServiceTrafficDistributionPreferClose = "PreferClose" ) // These are the valid conditions of a service. From da338ba1fffb6b0742a188252060fcd95e82848a Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 7 Oct 2025 10:59:50 -0400 Subject: [PATCH 5/5] Warn on use of deprecated PreferClose --- pkg/api/service/warnings.go | 4 ++++ pkg/api/service/warnings_test.go | 38 ++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/pkg/api/service/warnings.go b/pkg/api/service/warnings.go index 92fef3afa90..a9f0cdad25f 100644 --- a/pkg/api/service/warnings.go +++ b/pkg/api/service/warnings.go @@ -72,6 +72,10 @@ func GetWarningsForService(service, oldService *api.Service) []string { warnings = append(warnings, fmt.Sprintf("spec.externalName is ignored when spec.type is not %q", api.ServiceTypeExternalName)) } + if service.Spec.TrafficDistribution != nil && *service.Spec.TrafficDistribution == api.ServiceTrafficDistributionPreferClose { + warnings = append(warnings, fmt.Sprintf("spec.trafficDistribution: %q is deprecated; use %q", api.ServiceTrafficDistributionPreferClose, api.ServiceTrafficDistributionPreferSameZone)) + } + return warnings } diff --git a/pkg/api/service/warnings_test.go b/pkg/api/service/warnings_test.go index dcf2a2ade19..3fe97f7d7cb 100644 --- a/pkg/api/service/warnings_test.go +++ b/pkg/api/service/warnings_test.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/utils/ptr" ) func TestGetWarningsForService(t *testing.T) { @@ -90,18 +91,31 @@ func TestGetWarningsForService(t *testing.T) { s.Spec.SessionAffinity = api.ServiceAffinityNone }, numWarnings: 0, - }, - { - name: "ExternalIPs, LoadBalancerIP and SessionAffinity set when headless service", - tweakSvc: func(s *api.Service) { - s.Spec.Type = api.ServiceTypeClusterIP - s.Spec.ClusterIP = api.ClusterIPNone - s.Spec.ExternalIPs = []string{"1.2.3.4"} - s.Spec.LoadBalancerIP = "1.2.3.4" - s.Spec.SessionAffinity = api.ServiceAffinityClientIP - }, - numWarnings: 3, - }} + }, { + name: "ExternalIPs, LoadBalancerIP and SessionAffinity set when headless service", + tweakSvc: func(s *api.Service) { + s.Spec.Type = api.ServiceTypeClusterIP + s.Spec.ClusterIP = api.ClusterIPNone + s.Spec.ExternalIPs = []string{"1.2.3.4"} + s.Spec.LoadBalancerIP = "1.2.3.4" + s.Spec.SessionAffinity = api.ServiceAffinityClientIP + }, + numWarnings: 3, + }, { + name: "trafficDistribution: PreferSameZone", + tweakSvc: func(s *api.Service) { + s.Spec.Type = api.ServiceTypeClusterIP + s.Spec.TrafficDistribution = ptr.To(api.ServiceTrafficDistributionPreferSameZone) + }, + numWarnings: 0, + }, { + name: "trafficDistribution: PreferClose", + tweakSvc: func(s *api.Service) { + s.Spec.Type = api.ServiceTypeClusterIP + s.Spec.TrafficDistribution = ptr.To(api.ServiceTrafficDistributionPreferClose) + }, + numWarnings: 1, + }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) {