Change:
What happened: indicates that we're missing an e2e test for. This specific issue is just a tracker to create a new E2E test that demonstrated .
/sig network
/assign
btw, should this be a part of conformance?
/triage unresolved Comment when the issue is assessed and confirmed. I am a bot run by vllry. ‍
If this issue has been triaged, please comment . If you aren't able to handle this issue, consider unassigning yourself and/or adding the label. I am a bot run by vllry. ‍
/remove-triage unresolved
I can start working on this.
Sure/ are you working full time on it ? If so I'll drop the issue from my work ... Otherwise we can collaborate as I already have some code for this. Let me know. Was hoping to have this done in the next week or so.
I would love to collaborate, especially if you already have some code. But if you want to drop this from your work, I don't mind taking it on full time either. I can pick up from where ever you left off.
ok, if youve got full bandwidth go for it. if make progress on it this wk ill just drop it . I actually dont know where my old branch is for this :), so i guess youll have to start from scratch. One thing to note ~ Might be seeing if any tests can be reused for this or extended in a simple way by just adding a secondary service, rather then writing a full blown test from scratch. Let me know how it goes thanks !
I will let you know how it progresses. Thanks !
thanks for getting this taken care of :) looks like the PR is LGTM.
Thanks for letting me take a stab at it!

Discussion:
} func (config *NetworkingTestConfig) createNodePortService(selector map[string]string) { <del> config.NodePortService = config.createService(config.createNodePortServiceSpec(nodePortServiceName, selector, false)) </del> <ins> config.NodePortService = config.CreateService(config.createNodePortServiceSpec(nodePortServiceName, selector, false)) </ins> } func (config *NetworkingTestConfig) createSessionAffinityService(selector map[string]string) { <del> config.SessionAffinityService = config.createService(config.createNodePortServiceSpec(sessionAffinityServiceName, selector, true)) </del> <ins> config.SessionAffinityService = config.CreateService(config.createNodePortServiceSpec(sessionAffinityServiceName, selector, true)) </ins> } // DeleteNodePortService deletes NodePort service.

} } <del> func (config *NetworkingTestConfig) createService(serviceSpec *v1.Service) *v1.Service { </del> <ins> // CreateService creates the provided service in config.Namespace and returns created service func (config *NetworkingTestConfig) CreateService(serviceSpec *v1.Service) *v1.Service { </ins> _, err := config.getServiceClient().Create(context.TODO(), serviceSpec, metav1.CreateOptions{}) framework.ExpectNoError(err, fmt.Sprintf("Failed to create %s service: %v", serviceSpec.Name, err))

config.DialFromEndpointContainer("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames()) }) <ins> // This test ensures that in a situation where multiple services exist with the same selector, // deleting one of the services does not affect the connectivity of the remaining service ginkgo.It("should function for multiple endpoint-Services with same selector", func() { config := e2enetwork.NewNetworkingTestConfig(f, false, false) ginkgo.By("creating a second service with same selector") svc2, httpPort := createSecondNodePortService(f, config) // original service should work ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (config.clusterIP)", config.EndpointPods[0].Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) config.DialFromEndpointContainer("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (nodeIP)", config.EndpointPods[0].Name, config.NodeIP, config.NodeHTTPPort)) config.DialFromEndpointContainer("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) // Dial second service ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (svc2.clusterIP)", config.EndpointPods[0].Name, svc2.Spec.ClusterIP, e2enetwork.ClusterHTTPPort)) config.DialFromEndpointContainer("http", svc2.Spec.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (nodeIP)", config.EndpointPods[0].Name, config.NodeIP, httpPort)) config.DialFromEndpointContainer("http", config.NodeIP, httpPort, config.MaxTries, 0, config.EndpointHostnames()) ginkgo.By("deleting the original node port service") config.DeleteNodePortService() // Second service should continue to function unaffected ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (svc2.clusterIP)", config.EndpointPods[0].Name, svc2.Spec.ClusterIP, e2enetwork.ClusterHTTPPort)) config.DialFromEndpointContainer("http", svc2.Spec.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (nodeIP)", config.EndpointPods[0].Name, config.NodeIP, httpPort)) config.DialFromEndpointContainer("http", config.NodeIP, httpPort, config.MaxTries, 0, config.EndpointHostnames()) }) </ins> ginkgo.It("should update endpoints: http", func() { config := e2enetwork.NewNetworkingTestConfig(f, false, false) ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterHTTPPort))

v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" <ins> "k8s.io/apimachinery/pkg/util/intstr" </ins> "k8s.io/apimachinery/pkg/util/wait" "k8s.io/kubernetes/test/e2e/framework" e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"

imageutils "k8s.io/kubernetes/test/utils/image" ) <ins> // secondNodePortSvcName is the name of the secondary node port service const secondNodePortSvcName = "second-node-port-service" </ins> var ( // agnHostImage is the image URI of AgnHost agnHostImage = imageutils.GetE2EImage(imageutils.Agnhost)

} return sourcePod.Status.PodIP, host } <ins> // createSecondNodePortService creates a service with the same selector as config.NodePortService and same HTTP Port func createSecondNodePortService(f *framework.Framework, config *e2enetwork.NetworkingTestConfig) (*v1.Service, int) { svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: secondNodePortSvcName, }, Spec: v1.ServiceSpec{ Type: v1.ServiceTypeNodePort, Ports: []v1.ServicePort{ { Port:       e2enetwork.ClusterHTTPPort, Name:       "http", Protocol:   v1.ProtocolTCP, TargetPort: intstr.FromInt(e2enetwork.EndpointHTTPPort), }, }, Selector: config.NodePortService.Spec.Selector, }, } createdService := config.CreateService(svc) err := framework.WaitForServiceEndpointsNum(f.ClientSet, config.Namespace, secondNodePortSvcName, len(config.EndpointPods), time.Second, wait.ForeverTestTimeout) framework.ExpectNoError(err, "failed to validate endpoints for service %s in namespace: %s", secondNodePortSvcName, config.Namespace) var httpPort int for _, p := range createdService.Spec.Ports { switch p.Protocol { case v1.ProtocolTCP: httpPort = int(p.NodePort) default: continue } } return createdService, httpPort } </ins>