Change:
What happened: final passing output: What you expected to happen: Probably if this test passes, it should be showing several real endpoints. I don't know exactly what it does, but im assuming that the output could be clarified a little. How to reproduce it (as minimally and precisely as possible): run and look at the logs. Anything else we need to know?: Environment: Kubernetes version (use ): 1.20 (sonobuoy)
/sig-network
/assign
/triage accepted
^ an interesting case here was that was but there was no SIG (typo in the command that did). should the label be only if there is label on the ticket? /sig network
the PR that adds triage/accepeted automation () was merged 3 hours ago, but it'll "actually" get rolled out in the next prow bump. Mostly when merges. Thanks for flagging though, appreciate it! :)
sorry, missed the actual question! :woman_facepalming: (need moar coffee!! :coffee: ) I don't think we should require a label for adding the label. In case someone comments with the following, we'd still want it to be valid.
/triage unresolved Comment when the issue is assessed and confirmed. I am a bot run by vllry. ‍
The above test cleans up the By directives and so on, After reading through the test more its clear that every test sets up a scaffold measures a property of that scaffold sometimes deletes something that is recovered in that scaffold (i.e. a pod that is behind a UDP service) So, the thing that was confusing I guess to me is that we validate empty conditions (i.e. no pods available) once we delete a nodePort svc. Meanwhile also noticed that the original work to clean up error reporting needed to cascade over to these tests as well.Have just finished all that, and also updated comments to reflect the Todo around the statistical computation (we have the ability to do extra polling via but we don't actually have any test that leverages this.As a follow on I guess it would be nice if we did have a test that confirmed that pods were load balanced evenly, esp with the new proliferation of different proxy technologies , I.e. a (or something similar

Discussion:
framework.ConformanceIt("should function for node-pod communication: http [LinuxOnly] [NodeConformance]", func() { config := e2enetwork.NewCoreNetworkingTestConfig(f, true) for _, endpointPod := range config.EndpointPods { <del> config.DialFromNode("http", endpointPod.Status.PodIP, e2enetwork.EndpointHTTPPort, config.MaxTries, 0, sets.NewString(endpointPod.Name)) </del> <ins> err := config.DialFromNode("http", endpointPod.Status.PodIP, e2enetwork.EndpointHTTPPort, config.MaxTries, 0, sets.NewString(endpointPod.Name)) if err != nil { framework.Failf("Error dialing HTTP node to pod %v", err) } </ins> } })

framework.ConformanceIt("should function for node-pod communication: udp [LinuxOnly] [NodeConformance]", func() { config := e2enetwork.NewCoreNetworkingTestConfig(f, true) for _, endpointPod := range config.EndpointPods { <del> config.DialFromNode("udp", endpointPod.Status.PodIP, e2enetwork.EndpointUDPPort, config.MaxTries, 0, sets.NewString(endpointPod.Name)) </del> <ins> err := config.DialFromNode("udp", endpointPod.Status.PodIP, e2enetwork.EndpointUDPPort, config.MaxTries, 0, sets.NewString(endpointPod.Name)) if err != nil { framework.Failf("Error dialing UDP from node to pod: %v", err) } </ins> } }) })

return code, nil } <del> // DialFromNode executes a tcp or udp request based on protocol via kubectl exec </del> <ins> // DialFromNode executes a tcp/udp curl/nc request based on protocol via kubectl exec </ins> // in a test container running with host networking. <del> // - minTries is the minimum number of curl attempts required before declaring //   success. Set to 0 if you'd like to return as soon as all endpoints respond //   at least once. // - maxTries is the maximum number of curl attempts. If this many attempts pass //   and we don't see all expected endpoints, the test fails. // maxTries == minTries will confirm that we see the expected endpoints and no // more for maxTries. Use this if you want to eg: fail a readiness check on a // pod and confirm it doesn't show up as an endpoint. func (config *NetworkingTestConfig) DialFromNode(protocol, targetIP string, targetPort, maxTries, minTries int, expectedEps sets.String) { </del> <ins> // - minTries is the minimum number of curl/nc attempts required before declaring //   success. If 0, then we return as soon as all endpoints succeed. // - There is no logical change to test results if faillures happen AFTER endpoints have succeeded, //   hence over-padding minTries will NOT reverse a successful result and is thus not very useful yet //   (See the TODO about checking probability, which isnt implemented yet). // - maxTries is the maximum number of curl/echo attempts before an error is returned.  The //   smaller this number is, the less 'slack' there is for declaring success. // - if maxTries < expectedEps, this test is guaranteed to return an error, because all endpoints wont be hit. // - maxTries == minTries will return as soon as all endpoints succeed (or fail once maxTries is reached without //   success on all endpoints). //   In general its prudent to have a high enough level of minTries to guarantee that all pods get a fair chance at receiving traffic. func (config *NetworkingTestConfig) DialFromNode(protocol, targetIP string, targetPort, maxTries, minTries int, expectedEps sets.String) error { </ins> var cmd string if protocol == "udp" { cmd = fmt.Sprintf("echo hostName | nc -w 1 -u %s %d", targetIP, targetPort)

eps := sets.NewString() filterCmd := fmt.Sprintf("%s | grep -v '^s*$'", cmd) <ins> framework.Logf("Going to poll %v on port %v at least %v times, with a maximum of %v tries before failing", targetIP, targetPort, minTries, maxTries) </ins> for i := 0; i < maxTries; i++ { stdout, stderr, err := config.f.ExecShellInPodWithFullOutput(config.HostTestContainerPod.Name, filterCmd) if err != nil || len(stderr) > 0 {

// Check against i+1 so we exit if minTries == maxTries. if eps.Equal(expectedEps) && i+1 >= minTries { <del> framework.Logf("Found all expected endpoints: %+v", eps.List()) return </del> <ins> framework.Logf("Found all %d expected endpoints: %+v", eps.Len(), eps.List()) return nil </ins> } framework.Logf("Waiting for %+v endpoints (expected=%+v, actual=%+v)", expectedEps.Difference(eps).List(), expectedEps.List(), eps.List())

} config.diagnoseMissingEndpoints(eps) <del> framework.Failf("Failed to find expected endpoints:nTries %dnCommand %vnretrieved %vnexpected %vn", maxTries, cmd, eps, expectedEps) </del> <ins> return fmt.Errorf("failed to find expected endpoints, ntries %dnCommand %vnretrieved %vnexpected %v", maxTries, cmd, eps, expectedEps) </ins> } // GetSelfURL executes a curl against the given path via kubectl exec into a

ginkgo.It("should function for node-Service: http", func() { config := e2enetwork.NewNetworkingTestConfig(f, true, false) ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (config.clusterIP)", config.NodeIP, config.ClusterIP, e2enetwork.ClusterHTTPPort)) <del> config.DialFromNode("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> err := config.DialFromNode("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("failed dialing endpoint, %v", err) } </ins> ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) <del> config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> err = config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("failed dialing endpoint, %v", err) } </ins> }) ginkgo.It("should function for node-Service: udp", func() { config := e2enetwork.NewNetworkingTestConfig(f, true, false) ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (config.clusterIP)", config.NodeIP, config.ClusterIP, e2enetwork.ClusterUDPPort)) <del> config.DialFromNode("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> err := config.DialFromNode("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("failed dialing endpoint, %v", err) } </ins> ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeUDPPort)) <del> config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> err = config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("failed dialing endpoint, %v", err) } </ins> }) ginkgo.It("should function for endpoint-Service: http", func() {

ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) err := config.DialFromTestContainer("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { <del> framework.Failf("failed dialing endpoint, %v", err) </del> <ins> framework.Failf("failed dialing endpoint (initial), %v", err) </ins> } <ins> ginkgo.By("Deleting a pod which, will be replaced with a new endpoint") </ins> config.DeleteNetProxyPod() <del> ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP) (endpoint recovery)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) </ins> err = config.DialFromTestContainer("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, config.MaxTries, config.EndpointHostnames()) if err != nil { <del> framework.Failf("failed dialing endpoint, %v", err) </del> <ins> framework.Failf("failed dialing endpoint (recovery), %v", err) </ins> } })

ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterUDPPort)) err := config.DialFromTestContainer("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { <del> framework.Failf("failed dialing endpoint, %v", err) </del> <ins> framework.Failf("failed dialing endpoint (initial), %v", err) </ins> } <ins> ginkgo.By("Deleting a pod which, will be replaced with a new endpoint") </ins> config.DeleteNetProxyPod() <del> ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterUDPPort)) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP) (endpoint recovery)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterUDPPort)) </ins> err = config.DialFromTestContainer("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, config.MaxTries, config.EndpointHostnames()) if err != nil { <del> framework.Failf("failed dialing endpoint, %v", err) </del> <ins> framework.Failf("failed dialing endpoint (recovery), %v", err) </ins> } }) // Slow because we confirm that the nodePort doesn't serve traffic, which requires a period of polling. ginkgo.It("should update nodePort: http [Slow]", func() { config := e2enetwork.NewNetworkingTestConfig(f, true, false) <del> ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP) and getting ALL host endpoints", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) err := config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("Error dialing http from node: %v", err) } ginkgo.By("Deleting the node port access point") </ins> config.DeleteNodePortService() <del> ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, config.MaxTries, sets.NewString()) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP) and getting ZERO host endpoints", config.NodeIP, config.NodeIP, config.NodeHTTPPort)) err = config.DialFromNode("http", config.NodeIP, config.NodeHTTPPort, config.MaxTries, config.MaxTries, sets.NewString()) if err != nil { framework.Failf("Error dialing http from node: %v", err) } </ins> }) // Slow because we confirm that the nodePort doesn't serve traffic, which requires a period of polling. ginkgo.It("should update nodePort: udp [Slow]", func() { config := e2enetwork.NewNetworkingTestConfig(f, true, false) <del> ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeUDPPort)) config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames()) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP) and getting ALL host endpoints", config.NodeIP, config.NodeIP, config.NodeUDPPort)) err := config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { framework.Failf("Failure validating that nodePort service WAS forwarding properly: %v", err) } ginkgo.By("Deleting the node port access point") </ins> config.DeleteNodePortService() <del> ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP)", config.NodeIP, config.NodeIP, config.NodeUDPPort)) config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, config.MaxTries, sets.NewString()) </del> <ins> ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP) and getting ZERO host endpoints", config.NodeIP, config.NodeIP, config.NodeUDPPort)) err = config.DialFromNode("udp", config.NodeIP, config.NodeUDPPort, config.MaxTries, config.MaxTries, sets.NewString()) if err != nil { framework.Failf("Failure validating that node port service STOPPED removed properly: %v", err) } </ins> }) // [LinuxOnly]: Windows does not support session affinity.