From 2827b7ffb7ecd5894307a772d74a3bcca6a4dc44 Mon Sep 17 00:00:00 2001 From: Dane LeBlanc Date: Tue, 19 Sep 2017 17:29:29 -0400 Subject: [PATCH] Add brackets around IPv6 addrs in e2e test IP:port endpoints There are several locations in the e2e tests where endpoints of the form IP:port use IPv6 addresses directly, without surrounding brackets. Brackets are required around IPv6 addresses in this case, in order to distinguish the colons in the IPv6 address from the colon immediately preceding the port. Also, wherever the curl command might be used with an IPv6 address surrounded in brackets, the "-g" argument is added to the curl command line arguments so that the brackets can be interpreted correctly. fixes #52746 --- test/e2e/framework/networking_utils.go | 42 +++++++++++++++++--------- test/e2e/framework/service_util.go | 15 ++++++--- test/e2e/framework/util.go | 2 +- test/e2e/network/service.go | 15 ++++++--- test/images/nettest/nettest.go | 4 ++- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/test/e2e/framework/networking_utils.go b/test/e2e/framework/networking_utils.go index 643805b4fc..66d7e25527 100644 --- a/test/e2e/framework/networking_utils.go +++ b/test/e2e/framework/networking_utils.go @@ -179,9 +179,12 @@ func (config *NetworkingTestConfig) EndpointHostnames() sets.String { // 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) DialFromContainer(protocol, containerIP, targetIP string, containerHttpPort, targetPort, maxTries, minTries int, expectedEps sets.String) { - cmd := fmt.Sprintf("curl -q -s 'http://%s:%d/dial?request=hostName&protocol=%s&host=%s&port=%d&tries=1'", - containerIP, - containerHttpPort, + ipPort := net.JoinHostPort(containerIP, strconv.Itoa(containerHttpPort)) + // The current versions of curl included in CentOS and RHEL distros + // misinterpret square brackets around IPv6 as globbing, so use the -g + // argument to disable globbing to handle the IPv6 case. + cmd := fmt.Sprintf("curl -g -q -s 'http://%s/dial?request=hostName&protocol=%s&host=%s&port=%d&tries=1'", + ipPort, protocol, targetIP, targetPort) @@ -234,9 +237,12 @@ func (config *NetworkingTestConfig) GetEndpointsFromTestContainer(protocol, targ // - tries is the number of curl attempts. If this many attempts pass and // we don't see any endpoints, the test fails. func (config *NetworkingTestConfig) GetEndpointsFromContainer(protocol, containerIP, targetIP string, containerHttpPort, targetPort, tries int) (sets.String, error) { - cmd := fmt.Sprintf("curl -q -s 'http://%s:%d/dial?request=hostName&protocol=%s&host=%s&port=%d&tries=1'", - containerIP, - containerHttpPort, + ipPort := net.JoinHostPort(containerIP, strconv.Itoa(containerHttpPort)) + // The current versions of curl included in CentOS and RHEL distros + // misinterpret square brackets around IPv6 as globbing, so use the -g + // argument to disable globbing to handle the IPv6 case. + cmd := fmt.Sprintf("curl -g -q -s 'http://%s/dial?request=hostName&protocol=%s&host=%s&port=%d&tries=1'", + ipPort, protocol, targetIP, targetPort) @@ -289,7 +295,11 @@ func (config *NetworkingTestConfig) DialFromNode(protocol, targetIP string, targ // busybox timeout doesn't support non-integer values. cmd = fmt.Sprintf("echo 'hostName' | timeout -t 2 nc -w 1 -u %s %d", targetIP, targetPort) } else { - cmd = fmt.Sprintf("timeout -t 15 curl -q -s --connect-timeout 1 http://%s:%d/hostName", targetIP, targetPort) + ipPort := net.JoinHostPort(targetIP, strconv.Itoa(targetPort)) + // The current versions of curl included in CentOS and RHEL distros + // misinterpret square brackets around IPv6 as globbing, so use the -g + // argument to disable globbing to handle the IPv6 case. + cmd = fmt.Sprintf("timeout -t 15 curl -g -q -s --connect-timeout 1 http://%s/hostName", ipPort) } // TODO: This simply tells us that we can reach the endpoints. Check that @@ -736,7 +746,8 @@ func TestReachableHTTPWithContentTimeout(ip string, port int, request string, ex func TestReachableHTTPWithContentTimeoutWithRetriableErrorCodes(ip string, port int, request string, expect string, content *bytes.Buffer, retriableErrCodes []int, timeout time.Duration) (bool, error) { - url := fmt.Sprintf("http://%s:%d%s", ip, port, request) + ipPort := net.JoinHostPort(ip, strconv.Itoa(port)) + url := fmt.Sprintf("http://%s%s", ipPort, request) if ip == "" { Failf("Got empty IP for reachability check (%s)", url) return false, nil @@ -783,7 +794,8 @@ func TestNotReachableHTTP(ip string, port int) (bool, error) { } func TestNotReachableHTTPTimeout(ip string, port int, timeout time.Duration) (bool, error) { - url := fmt.Sprintf("http://%s:%d", ip, port) + ipPort := net.JoinHostPort(ip, strconv.Itoa(port)) + url := fmt.Sprintf("http://%s", ipPort) if ip == "" { Failf("Got empty IP for non-reachability check (%s)", url) return false, nil @@ -805,7 +817,8 @@ func TestNotReachableHTTPTimeout(ip string, port int, timeout time.Duration) (bo } func TestReachableUDP(ip string, port int, request string, expect string) (bool, error) { - uri := fmt.Sprintf("udp://%s:%d", ip, port) + ipPort := net.JoinHostPort(ip, strconv.Itoa(port)) + uri := fmt.Sprintf("udp://%s", ipPort) if ip == "" { Failf("Got empty IP for reachability check (%s)", uri) return false, nil @@ -817,9 +830,9 @@ func TestReachableUDP(ip string, port int, request string, expect string) (bool, Logf("Testing UDP reachability of %v", uri) - con, err := net.Dial("udp", ip+":"+strconv.Itoa(port)) + con, err := net.Dial("udp", ipPort) if err != nil { - return false, fmt.Errorf("Failed to dial %s:%d: %v", ip, port, err) + return false, fmt.Errorf("Failed to dial %s: %v", ipPort, err) } _, err = con.Write([]byte(fmt.Sprintf("%s\n", request))) @@ -848,7 +861,8 @@ func TestReachableUDP(ip string, port int, request string, expect string) (bool, } func TestNotReachableUDP(ip string, port int, request string) (bool, error) { - uri := fmt.Sprintf("udp://%s:%d", ip, port) + ipPort := net.JoinHostPort(ip, strconv.Itoa(port)) + uri := fmt.Sprintf("udp://%s", ipPort) if ip == "" { Failf("Got empty IP for reachability check (%s)", uri) return false, nil @@ -860,7 +874,7 @@ func TestNotReachableUDP(ip string, port int, request string) (bool, error) { Logf("Testing UDP non-reachability of %v", uri) - con, err := net.Dial("udp", ip+":"+strconv.Itoa(port)) + con, err := net.Dial("udp", ipPort) if err != nil { Logf("Confirmed that %s is not reachable", uri) return true, nil diff --git a/test/e2e/framework/service_util.go b/test/e2e/framework/service_util.go index cfb3ebdf27..934c044a7e 100644 --- a/test/e2e/framework/service_util.go +++ b/test/e2e/framework/service_util.go @@ -19,6 +19,7 @@ package framework import ( "bytes" "fmt" + "net" "sort" "strconv" "strings" @@ -878,7 +879,8 @@ func (j *ServiceTestJig) GetHTTPContent(host string, port int, timeout time.Dura } func testHTTPHealthCheckNodePort(ip string, port int, request string) (bool, error) { - url := fmt.Sprintf("http://%s:%d%s", ip, port, request) + ipPort := net.JoinHostPort(ip, strconv.Itoa(port)) + url := fmt.Sprintf("http://%s%s", ipPort, request) if ip == "" || port == 0 { Failf("Got empty IP for reachability check (%s)", url) return false, fmt.Errorf("Invalid input ip or port") @@ -1292,8 +1294,9 @@ func VerifyServeHostnameServiceUp(c clientset.Interface, ns, host string, expect // Loop a bunch of times - the proxy is randomized, so we want a good // chance of hitting each backend at least once. buildCommand := func(wget string) string { - return fmt.Sprintf("for i in $(seq 1 %d); do %s http://%s:%d 2>&1 || true; echo; done", - 50*len(expectedPods), wget, serviceIP, servicePort) + serviceIPPort := net.JoinHostPort(serviceIP, strconv.Itoa(servicePort)) + return fmt.Sprintf("for i in $(seq 1 %d); do %s http://%s 2>&1 || true; echo; done", + 50*len(expectedPods), wget, serviceIPPort) } commands := []func() string{ // verify service from node @@ -1360,8 +1363,12 @@ func VerifyServeHostnameServiceUp(c clientset.Interface, ns, host string, expect } func VerifyServeHostnameServiceDown(c clientset.Interface, host string, serviceIP string, servicePort int) error { + ipPort := net.JoinHostPort(serviceIP, strconv.Itoa(servicePort)) + // The current versions of curl included in CentOS and RHEL distros + // misinterpret square brackets around IPv6 as globbing, so use the -g + // argument to disable globbing to handle the IPv6 case. command := fmt.Sprintf( - "curl -s --connect-timeout 2 http://%s:%d && exit 99", serviceIP, servicePort) + "curl -g -s --connect-timeout 2 http://%s && exit 99", ipPort) for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) { result, err := SSH(command, host, TestContext.Provider) diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index bddeeeb363..4105e90cdd 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -4496,7 +4496,7 @@ func LaunchWebserverPod(f *Framework, podName, nodeName string) (ip string) { ExpectNoError(f.WaitForPodRunning(podName)) createdPod, err := podClient.Get(podName, metav1.GetOptions{}) ExpectNoError(err) - ip = fmt.Sprintf("%s:%d", createdPod.Status.PodIP, port) + ip = net.JoinHostPort(createdPod.Status.PodIP, strconv.Itoa(port)) Logf("Target pod IP:port is %s", ip) return } diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 5bf65d1a80..2a9ec84eb5 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -20,6 +20,8 @@ import ( "bytes" "fmt" "math/rand" + "net" + "strconv" "strings" "time" @@ -1641,7 +1643,9 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { // Confirm traffic can reach backend through LB before checking healthcheck nodeport. jig.TestReachableHTTP(ingressIP, svcTCPPort, framework.KubeProxyLagTimeout) expectedSuccess := nodes.Items[n].Name == endpointNodeName - framework.Logf("Health checking %s, http://%s:%d%s, expectedSuccess %v", nodes.Items[n].Name, publicIP, healthCheckNodePort, path, expectedSuccess) + port := strconv.Itoa(healthCheckNodePort) + ipPort := net.JoinHostPort(publicIP, port) + framework.Logf("Health checking %s, http://%s%s, expectedSuccess %v", nodes.Items[n].Name, ipPort, path, expectedSuccess) Expect(jig.TestHTTPHealthCheckNodePort(publicIP, healthCheckNodePort, path, framework.KubeProxyEndpointLagTimeout, expectedSuccess, threshold)).NotTo(HaveOccurred()) } framework.ExpectNoError(framework.DeleteRCAndPods(f.ClientSet, f.InternalClientset, namespace, serviceName)) @@ -1662,7 +1666,9 @@ var _ = SIGDescribe("ESIPP [Slow]", func() { }() ingressIP := framework.GetIngressPoint(&svc.Status.LoadBalancer.Ingress[0]) - path := fmt.Sprintf("%s:%d/clientip", ingressIP, int(svc.Spec.Ports[0].Port)) + port := strconv.Itoa(int(svc.Spec.Ports[0].Port)) + ipPort := net.JoinHostPort(ingressIP, port) + path := fmt.Sprintf("%s/clientip", ipPort) nodeName := nodes.Items[0].Name podName := "execpod-sourceip" @@ -1813,9 +1819,10 @@ func execSourceipTest(f *framework.Framework, c clientset.Interface, ns, nodeNam framework.ExpectNoError(err) var stdout string + serviceIPPort := net.JoinHostPort(serviceIP, strconv.Itoa(servicePort)) timeout := 2 * time.Minute - framework.Logf("Waiting up to %v wget %s:%d", timeout, serviceIP, servicePort) - cmd := fmt.Sprintf(`wget -T 30 -qO- %s:%d | grep client_address`, serviceIP, servicePort) + framework.Logf("Waiting up to %v wget %s", timeout, serviceIPPort) + cmd := fmt.Sprintf(`wget -T 30 -qO- %s | grep client_address`, serviceIPPort) for start := time.Now(); time.Since(start) < timeout; time.Sleep(2) { stdout, err = framework.RunHostCmd(execPod.Namespace, execPod.Name, cmd) if err != nil { diff --git a/test/images/nettest/nettest.go b/test/images/nettest/nettest.go index bc065f83f9..09f92f4788 100644 --- a/test/images/nettest/nettest.go +++ b/test/images/nettest/nettest.go @@ -36,6 +36,7 @@ import ( "fmt" "io/ioutil" "log" + "net" "net/http" "os" "os/signal" @@ -278,7 +279,8 @@ func getWebserverEndpoints(client clientset.Interface) sets.String { for _, ss := range endpoints.Subsets { for _, a := range ss.Addresses { for _, p := range ss.Ports { - eps.Insert(fmt.Sprintf("http://%s:%d", a.IP, p.Port)) + ipPort := net.JoinHostPort(a.IP, fmt.Sprint(p.Port)) + eps.Insert(fmt.Sprintf("http://%s", ipPort)) } } }