From 734d5bbed07dfcee1a4ce841283618883ba9cfc8 Mon Sep 17 00:00:00 2001 From: Antonio Ojea Date: Mon, 26 Oct 2020 12:01:06 +0100 Subject: [PATCH] e2e use functional options to configure NetworkingTest NetworkingTest is used to test different network scenarios. Since new capabilites and scenarios are added, like SCTP or HostNetwork for pods, we need a way to configure it with minimum disruption and code changes. Go idiomatic way to achieve this is using functional options. --- test/e2e/framework/network/utils.go | 45 ++++++++++++++++++++++++++--- test/e2e/network/networking.go | 38 ++++++++++++------------ test/e2e/network/service.go | 8 ++--- 3 files changed, 64 insertions(+), 27 deletions(-) diff --git a/test/e2e/framework/network/utils.go b/test/e2e/framework/network/utils.go index 2f23633752c..194937c4d73 100644 --- a/test/e2e/framework/network/utils.go +++ b/test/e2e/framework/network/utils.go @@ -90,9 +90,34 @@ const ( // NetexecImageName is the image name for agnhost. var NetexecImageName = imageutils.GetE2EImage(imageutils.Agnhost) +// Option is used to configure the NetworkingTest object +type Option func(*NetworkingTestConfig) + +// EnableSCTP listen on SCTP ports on the endpoints +func EnableSCTP(config *NetworkingTestConfig) { + config.SCTPEnabled = true +} + +// UseHostNetwork run the test container with HostNetwork=true. +func UseHostNetwork(config *NetworkingTestConfig) { + config.HostNetwork = true +} + +// EndpointsUseHostNetwork run the endpoints pods with HostNetwork=true. +func EndpointsUseHostNetwork(config *NetworkingTestConfig) { + config.EndpointsHostNetwork = true +} + // NewNetworkingTestConfig creates and sets up a new test config helper. -func NewNetworkingTestConfig(f *framework.Framework, hostNetwork, SCTPEnabled bool) *NetworkingTestConfig { - config := &NetworkingTestConfig{f: f, Namespace: f.Namespace.Name, HostNetwork: hostNetwork, SCTPEnabled: SCTPEnabled} +func NewNetworkingTestConfig(f *framework.Framework, setters ...Option) *NetworkingTestConfig { + // default options + config := &NetworkingTestConfig{ + f: f, + Namespace: f.Namespace.Name, + } + for _, setter := range setters { + setter(config) + } ginkgo.By(fmt.Sprintf("Performing setup for networking test in namespace %v", config.Namespace)) config.setup(getServiceSelector()) return config @@ -100,7 +125,12 @@ func NewNetworkingTestConfig(f *framework.Framework, hostNetwork, SCTPEnabled bo // NewCoreNetworkingTestConfig creates and sets up a new test config helper for Node E2E. func NewCoreNetworkingTestConfig(f *framework.Framework, hostNetwork bool) *NetworkingTestConfig { - config := &NetworkingTestConfig{f: f, Namespace: f.Namespace.Name, HostNetwork: hostNetwork} + // default options + config := &NetworkingTestConfig{ + f: f, + Namespace: f.Namespace.Name, + HostNetwork: hostNetwork, + } ginkgo.By(fmt.Sprintf("Performing setup for networking test in namespace %v", config.Namespace)) config.setupCore(getServiceSelector()) return config @@ -125,6 +155,8 @@ type NetworkingTestConfig struct { HostTestContainerPod *v1.Pod // if the HostTestContainerPod is running with HostNetwork=true. HostNetwork bool + // if the endpoints Pods are running with HostNetwork=true. + EndpointsHostNetwork bool // if the test pods are listening on sctp port. We need this as sctp tests // are marked as disruptive as they may load the sctp module. SCTPEnabled bool @@ -213,7 +245,11 @@ func (config *NetworkingTestConfig) diagnoseMissingEndpoints(foundEndpoints sets func (config *NetworkingTestConfig) EndpointHostnames() sets.String { expectedEps := sets.NewString() for _, p := range config.EndpointPods { - expectedEps.Insert(p.Name) + if config.EndpointsHostNetwork { + expectedEps.Insert(p.Spec.NodeSelector["kubernetes.io/hostname"]) + } else { + expectedEps.Insert(p.Name) + } } return expectedEps } @@ -745,6 +781,7 @@ func (config *NetworkingTestConfig) createNetProxyPods(podName string, selector hostname, _ := n.Labels["kubernetes.io/hostname"] pod := config.createNetShellPodSpec(podName, hostname) pod.ObjectMeta.Labels = selector + pod.Spec.HostNetwork = config.EndpointsHostNetwork createdPod := config.createPod(pod) createdPods = append(createdPods, createdPod) } diff --git a/test/e2e/network/networking.go b/test/e2e/network/networking.go index c620466aa94..983d7dbb5db 100644 --- a/test/e2e/network/networking.go +++ b/test/e2e/network/networking.go @@ -136,7 +136,7 @@ var _ = SIGDescribe("Networking", func() { ginkgo.It("should check kube-proxy urls", func() { // TODO: this is overkill we just need the host networking pod // to hit kube-proxy urls. - config := e2enetwork.NewNetworkingTestConfig(f, true, false) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) ginkgo.By("checking kube-proxy URLs") config.GetSelfURL(ports.ProxyHealthzPort, "/healthz", "200 OK") @@ -149,7 +149,7 @@ var _ = SIGDescribe("Networking", func() { ginkgo.Describe("Granular Checks: Services", func() { ginkgo.It("should function for pod-Service: http", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) 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 { @@ -164,7 +164,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should function for pod-Service: udp", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) 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 { @@ -181,7 +181,7 @@ var _ = SIGDescribe("Networking", func() { // Once basic tests checking for the sctp module not to be loaded are implemented, this // needs to be marked as [Disruptive] ginkgo.It("should function for pod-Service: sctp [Feature:SCTPConnectivity][Disruptive]", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, true) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.EnableSCTP) ginkgo.By(fmt.Sprintf("dialing(sctp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterSCTPPort)) err := config.DialFromTestContainer("sctp", config.ClusterIP, e2enetwork.ClusterSCTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { @@ -195,7 +195,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should function for node-Service: http", func() { - config := e2enetwork.NewNetworkingTestConfig(f, true, false) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (config.clusterIP)", config.NodeIP, config.ClusterIP, e2enetwork.ClusterHTTPPort)) err := config.DialFromNode("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { @@ -209,7 +209,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should function for node-Service: udp", func() { - config := e2enetwork.NewNetworkingTestConfig(f, true, false) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (config.clusterIP)", config.NodeIP, config.ClusterIP, e2enetwork.ClusterUDPPort)) err := config.DialFromNode("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { @@ -223,7 +223,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should function for endpoint-Service: http", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (config.clusterIP)", config.EndpointPods[0].Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) err := config.DialFromEndpointContainer("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { @@ -237,7 +237,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should function for endpoint-Service: udp", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(udp) %v (endpoint) --> %v:%v (config.clusterIP)", config.EndpointPods[0].Name, config.ClusterIP, e2enetwork.ClusterUDPPort)) err := config.DialFromEndpointContainer("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames()) if err != nil { @@ -254,7 +254,7 @@ var _ = SIGDescribe("Networking", func() { // 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) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By("creating a second service with same selector") svc2, httpPort := createSecondNodePortService(f, config) @@ -299,7 +299,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should update endpoints: http", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) 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 { @@ -316,7 +316,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should update endpoints: udp", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) 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 { @@ -334,7 +334,7 @@ var _ = SIGDescribe("Networking", func() { // 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) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) 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 { @@ -352,7 +352,7 @@ var _ = SIGDescribe("Networking", func() { // quick validation of udp, next test confirms that this services update as well after endpoints are removed, but is slower. ginkgo.It("should support basic nodePort: udp functionality", func() { - config := e2enetwork.NewNetworkingTestConfig(f, true, false) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) 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 { @@ -362,7 +362,7 @@ var _ = SIGDescribe("Networking", func() { // 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) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.UseHostNetwork) 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 { @@ -381,7 +381,7 @@ var _ = SIGDescribe("Networking", func() { // [LinuxOnly]: Windows does not support session affinity. ginkgo.It("should function for client IP based session affinity: http [LinuxOnly]", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIP, e2enetwork.ClusterHTTPPort)) // Check if number of endpoints returned are exactly one. @@ -399,7 +399,7 @@ var _ = SIGDescribe("Networking", func() { // [LinuxOnly]: Windows does not support session affinity. ginkgo.It("should function for client IP based session affinity: udp [LinuxOnly]", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIP, e2enetwork.ClusterUDPPort)) // Check if number of endpoints returned are exactly one. @@ -416,7 +416,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should be able to handle large requests: http", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterHTTPPort)) message := strings.Repeat("42", 1000) err := config.DialEchoFromTestContainer("http", config.ClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, message) @@ -426,7 +426,7 @@ var _ = SIGDescribe("Networking", func() { }) ginkgo.It("should be able to handle large requests: udp", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterUDPPort)) message := "n" + strings.Repeat("o", 1999) err := config.DialEchoFromTestContainer("udp", config.ClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, message) @@ -439,7 +439,7 @@ var _ = SIGDescribe("Networking", func() { // Once basic tests checking for the sctp module not to be loaded are implemented, this // needs to be marked as [Disruptive] ginkgo.It("should function for pod-pod: sctp [Feature:SCTPConnectivity][Disruptive]", func() { - config := e2enetwork.NewNetworkingTestConfig(f, false, true) + config := e2enetwork.NewNetworkingTestConfig(f, e2enetwork.EnableSCTP) ginkgo.By(fmt.Sprintf("dialing(sctp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, e2enetwork.ClusterSCTPPort)) message := "hello" err := config.DialEchoFromTestContainer("sctp", config.TestContainerPod.Status.PodIP, e2enetwork.EndpointSCTPPort, config.MaxTries, 0, message) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 488143b901c..f37ef90d674 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -2997,7 +2997,7 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { const threshold = 2 nodes, err := getEndpointNodesWithInternalIP(jig) framework.ExpectNoError(err) - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) for _, internalIP := range nodes { err := testHTTPHealthCheckNodePortFromTestContainer( config, @@ -3044,7 +3044,7 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { framework.ExpectNoError(err) dialCmd := "clientip" - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) for nodeName, nodeIP := range endpointsNodeMap { ginkgo.By(fmt.Sprintf("reading clientIP using the TCP service's NodePort, on node %v: %v:%v/%v", nodeName, nodeIP, tcpNodePort, dialCmd)) @@ -3095,7 +3095,7 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { svcTCPPort := int(svc.Spec.Ports[0].Port) const threshold = 2 - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) for i := 0; i < len(nodes.Items); i++ { endpointNodeName := nodes.Items[i].Name @@ -3260,7 +3260,7 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { path := "/clientip" dialCmd := "clientip" - config := e2enetwork.NewNetworkingTestConfig(f, false, false) + config := e2enetwork.NewNetworkingTestConfig(f) ginkgo.By(fmt.Sprintf("endpoints present on nodes %v, absent on nodes %v", endpointNodeMap, noEndpointNodeMap)) for nodeName, nodeIP := range noEndpointNodeMap {