diff --git a/test/e2e/framework/endpointslice/wait.go b/test/e2e/framework/endpointslice/wait.go new file mode 100644 index 00000000000..f7f7f7eb167 --- /dev/null +++ b/test/e2e/framework/endpointslice/wait.go @@ -0,0 +1,45 @@ +/* +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 endpointslice + +import ( + "context" + "fmt" + "time" + + discoveryv1 "k8s.io/api/discovery/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" +) + +type EndpointSliceConditionFunc func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (done bool, err error) + +// WaitForEndpointSlices is an EndpointSlice-specific wrapper around +// wait.PollUntilContextTimeout that polls conditionFunc with a list of serviceName's +// EndpointSlices. +func WaitForEndpointSlices(ctx context.Context, cs clientset.Interface, namespace, serviceName string, interval, timeout time.Duration, conditionFunc EndpointSliceConditionFunc) error { + return wait.PollUntilContextTimeout(ctx, interval, timeout, true, func(ctx context.Context) (bool, error) { + esList, err := cs.DiscoveryV1().EndpointSlices(namespace).List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", discoveryv1.LabelServiceName, serviceName)}) + if err != nil { + framework.Logf("Unexpected error trying to get EndpointSlices for %s/%s: %v", namespace, serviceName, err) + return false, nil + } + return conditionFunc(ctx, esList.Items) + }) +} diff --git a/test/e2e/network/networking_perf.go b/test/e2e/network/networking_perf.go index 62e72dd7434..3fff2eb4bd0 100644 --- a/test/e2e/network/networking_perf.go +++ b/test/e2e/network/networking_perf.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/test/e2e/framework" e2edaemonset "k8s.io/kubernetes/test/e2e/framework/daemonset" e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment" + e2eendpointslice "k8s.io/kubernetes/test/e2e/framework/endpointslice" e2enode "k8s.io/kubernetes/test/e2e/framework/node" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" "k8s.io/kubernetes/test/e2e/network/common" @@ -170,12 +171,8 @@ var _ = common.SIGDescribe("Networking IPerf2", feature.NetworkingPerformance, f // Make sure the server is ready to go framework.Logf("waiting for iperf2 server endpoints") - err = wait.Poll(2*time.Second, largeClusterTimeout, func() (done bool, err error) { - listOptions := metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", discoveryv1.LabelServiceName, serverServiceName)} - esList, err := f.ClientSet.DiscoveryV1().EndpointSlices(f.Namespace.Name).List(ctx, listOptions) - framework.ExpectNoError(err, "Error fetching EndpointSlice for Service %s/%s", f.Namespace.Name, serverServiceName) - - if len(esList.Items) == 0 { + err = e2eendpointslice.WaitForEndpointSlices(ctx, f.ClientSet, f.Namespace.Name, serverServiceName, 2*time.Second, largeClusterTimeout, func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (bool, error) { + if len(endpointSlices) == 0 { framework.Logf("EndpointSlice for Service %s/%s not found", f.Namespace.Name, serverServiceName) return false, nil } diff --git a/test/e2e/network/pod_lifecycle.go b/test/e2e/network/pod_lifecycle.go index bd9df420b81..a7a246f111f 100644 --- a/test/e2e/network/pod_lifecycle.go +++ b/test/e2e/network/pod_lifecycle.go @@ -26,12 +26,14 @@ import ( "github.com/onsi/ginkgo/v2" v1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/test/e2e/framework" + e2eendpointslice "k8s.io/kubernetes/test/e2e/framework/endpointslice" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" e2eservice "k8s.io/kubernetes/test/e2e/framework/service" @@ -162,14 +164,8 @@ var _ = common.SIGDescribe("Connectivity Pod Lifecycle", func() { } // Expect EndpointSlice resource to have the blue pod ready to serve traffic - if err := wait.PollUntilContextTimeout(ctx, 2*time.Second, wait.ForeverTestTimeout, true, func(context.Context) (bool, error) { - endpointSliceList, err := cs.DiscoveryV1().EndpointSlices(blueGreenJig.Namespace).List(ctx, metav1.ListOptions{ - LabelSelector: "kubernetes.io/service-name=" + blueGreenJig.Name, - }) - if err != nil { - return false, err - } - for _, slice := range endpointSliceList.Items { + if err := e2eendpointslice.WaitForEndpointSlices(ctx, cs, blueGreenJig.Namespace, blueGreenJig.Name, 2*time.Second, wait.ForeverTestTimeout, func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (bool, error) { + for _, slice := range endpointSlices { for _, ep := range slice.Endpoints { if ep.TargetRef != nil && ep.TargetRef.Name == bluePod.Name && @@ -220,14 +216,8 @@ var _ = common.SIGDescribe("Connectivity Pod Lifecycle", func() { } // Expect EndpointSlice resource to have the green pod ready to serve traffic - if err := wait.PollUntilContextTimeout(ctx, 2*time.Second, wait.ForeverTestTimeout, true, func(context.Context) (bool, error) { - endpointSliceList, err := cs.DiscoveryV1().EndpointSlices(blueGreenJig.Namespace).List(ctx, metav1.ListOptions{ - LabelSelector: "kubernetes.io/service-name=" + blueGreenJig.Name, - }) - if err != nil { - return false, err - } - for _, slice := range endpointSliceList.Items { + if err := e2eendpointslice.WaitForEndpointSlices(ctx, cs, blueGreenJig.Namespace, blueGreenJig.Name, 2*time.Second, wait.ForeverTestTimeout, func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (bool, error) { + for _, slice := range endpointSlices { for _, ep := range slice.Endpoints { if ep.TargetRef != nil && ep.TargetRef.Name == greenPod.Name && @@ -249,14 +239,8 @@ var _ = common.SIGDescribe("Connectivity Pod Lifecycle", func() { } // Expect EndpointSlice resource to have the blue pod NOT ready to serve traffic - if err := wait.PollUntilContextTimeout(ctx, 2*time.Second, wait.ForeverTestTimeout, true, func(context.Context) (bool, error) { - endpointSliceList, err := cs.DiscoveryV1().EndpointSlices(blueGreenJig.Namespace).List(ctx, metav1.ListOptions{ - LabelSelector: "kubernetes.io/service-name=" + blueGreenJig.Name, - }) - if err != nil { - return false, err - } - for _, slice := range endpointSliceList.Items { + if err := e2eendpointslice.WaitForEndpointSlices(ctx, cs, blueGreenJig.Namespace, blueGreenJig.Name, 2*time.Second, wait.ForeverTestTimeout, func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (bool, error) { + for _, slice := range endpointSlices { for _, ep := range slice.Endpoints { if ep.TargetRef != nil && ep.TargetRef.Name == bluePod.Name &&