From 755a7261ee0281376a69096357141371e1c49866 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 18 Feb 2026 12:34:49 -0500 Subject: [PATCH 1/2] Fix some dual-stack tests to use svc.Spec.IPFamilies --- test/e2e/framework/network/utils.go | 13 ++++--------- test/e2e/network/service.go | 11 ++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/test/e2e/framework/network/utils.go b/test/e2e/framework/network/utils.go index 30da5df9484..65e31d31dcb 100644 --- a/test/e2e/framework/network/utils.go +++ b/test/e2e/framework/network/utils.go @@ -47,7 +47,6 @@ import ( e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" imageutils "k8s.io/kubernetes/test/utils/image" - netutils "k8s.io/utils/net" ) const ( @@ -838,14 +837,10 @@ func (config *NetworkingTestConfig) setup(ctx context.Context, selector map[stri config.SecondaryClusterIP = config.NodePortService.Spec.ClusterIPs[1] } - // Obtain the primary IP family of the Cluster based on the first ClusterIP - // TODO: Eventually we should just be getting these from Spec.IPFamilies - // but for now that would only if the feature gate is enabled. - family := v1.IPv4Protocol - secondaryFamily := v1.IPv6Protocol - if netutils.IsIPv6String(config.ClusterIP) { - family = v1.IPv6Protocol - secondaryFamily = v1.IPv4Protocol + var family, secondaryFamily v1.IPFamily + family = config.NodePortService.Spec.IPFamilies[0] + if len(config.NodePortService.Spec.IPFamilies) == 2 { + secondaryFamily = config.NodePortService.Spec.IPFamilies[1] } if config.PreferExternalAddresses { // Get Node IPs from the cluster, ExternalIPs take precedence diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 4ae4c72ceb2..f1cd06b3e7d 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -54,7 +54,6 @@ import ( "k8s.io/client-go/util/retry" cloudprovider "k8s.io/cloud-provider" - netutils "k8s.io/utils/net" "k8s.io/utils/ptr" podutil "k8s.io/kubernetes/pkg/api/v1/pod" @@ -4210,10 +4209,7 @@ func execAffinityTestForSessionAffinityTimeout(ctx context.Context, f *framework nodes, err := e2enode.GetReadySchedulableNodes(ctx, cs) framework.ExpectNoError(err) // The node addresses must have the same IP family as the ClusterIP - family := v1.IPv4Protocol - if netutils.IsIPv6String(svc.Spec.ClusterIP) { - family = v1.IPv6Protocol - } + family := svc.Spec.IPFamilies[0] svcIP = e2enode.FirstAddressByTypeAndFamily(nodes, v1.NodeInternalIP, family) if svcIP == "" { svcIP = e2enode.FirstAddressByTypeAndFamily(nodes, v1.NodeExternalIP, family) @@ -4296,10 +4292,7 @@ func execAffinityTestForNonLBServiceWithOptionalTransition(ctx context.Context, nodes, err := e2enode.GetReadySchedulableNodes(ctx, cs) framework.ExpectNoError(err) // The node addresses must have the same IP family as the ClusterIP - family := v1.IPv4Protocol - if netutils.IsIPv6String(svc.Spec.ClusterIP) { - family = v1.IPv6Protocol - } + family := svc.Spec.IPFamilies[0] svcIP = e2enode.FirstAddressByTypeAndFamily(nodes, v1.NodeInternalIP, family) if svcIP == "" { svcIP = e2enode.FirstAddressByTypeAndFamily(nodes, v1.NodeExternalIP, family) From 05ca65743419c4a56a6552b0c48db00d12231405 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 18 Feb 2026 12:37:27 -0500 Subject: [PATCH 2/2] Rewrite an incorrect dual-stack e2e test The test was previously asserting that in a dual-stack cluster, every node had exactly 2 InternalIPs, where 1 was IPv4 and 1 was IPv6. Even ignoring the possibility of having some single-stack nodes in a dual-stack cluster, this test was wrong since (a) it didn't allow nodes to have additional non-primary node IPs, and (b) it discriminated against ExternalIPs. Fix it to just assert that in a dual-stack cluster, at least 1 node has at least 1 IPv4 IP and at least 1 IPv6 IP. --- test/e2e/network/dual_stack.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/test/e2e/network/dual_stack.go b/test/e2e/network/dual_stack.go index ffd3ece47f4..9abfb13cca4 100644 --- a/test/e2e/network/dual_stack.go +++ b/test/e2e/network/dual_stack.go @@ -58,20 +58,35 @@ var _ = common.SIGDescribe(feature.IPv6DualStack, func() { podClient = e2epod.NewPodClient(f) }) - ginkgo.It("should have ipv4 and ipv6 internal node ip", func(ctx context.Context) { - // TODO (aramase) can switch to new function to get all nodes + // A dual-stack cluster should have at least one dual-stack node (though it may + // also have some single-stack IPv4 or single-stack IPv6 nodes for some use + // cases). + ginkgo.It("should have at least one dual-stack node", func(ctx context.Context) { nodeList, err := e2enode.GetReadySchedulableNodes(ctx, cs) framework.ExpectNoError(err) + var found bool for _, node := range nodeList.Items { - // get all internal ips for node - internalIPs := e2enode.GetAddresses(&node, v1.NodeInternalIP) - - gomega.Expect(internalIPs).To(gomega.HaveLen(2)) - // assert 2 ips belong to different families - if netutils.IsIPv4String(internalIPs[0]) == netutils.IsIPv4String(internalIPs[1]) { - framework.Failf("both internalIPs %s and %s belong to the same families", internalIPs[0], internalIPs[1]) + ginkgo.By(fmt.Sprintf("examining %s", node.Name)) + var hasIPv4, hasIPv6 bool + for _, addr := range node.Status.Addresses { + if addr.Type != v1.NodeInternalIP && addr.Type != v1.NodeExternalIP { + continue + } + if netutils.IsIPv4String(addr.Address) { + hasIPv4 = true + } else if netutils.IsIPv6String(addr.Address) { + hasIPv6 = true + } } + if hasIPv4 && hasIPv6 { + found = true + break + } + } + + if !found { + framework.Failf("Could not find any schedulable node with both an IPv4 IP and an IPv6 IP") } })