diff --git a/build/dependencies.yaml b/build/dependencies.yaml index 31e54376458..1a735592adf 100644 --- a/build/dependencies.yaml +++ b/build/dependencies.yaml @@ -116,6 +116,8 @@ dependencies: match: debian_iptables_version= - path: build/workspace.bzl match: tag = + - path: test/utils/image/manifest.go + match: configs\[DebianIptables\] = Config{buildImageRegistry, "debian-iptables", "v\d+\.\d+.\d+"} - name: "k8s.gcr.io/go-runner" version: 0.1.1 diff --git a/test/e2e/network/kube_proxy.go b/test/e2e/network/kube_proxy.go index 6101a9e7dab..8cc2aab7599 100644 --- a/test/e2e/network/kube_proxy.go +++ b/test/e2e/network/kube_proxy.go @@ -18,7 +18,6 @@ package network import ( "context" - "encoding/hex" "fmt" "math" "net" @@ -35,6 +34,7 @@ import ( e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" imageutils "k8s.io/kubernetes/test/utils/image" + netutils "k8s.io/utils/net" "github.com/onsi/ginkgo" "github.com/onsi/gomega" @@ -81,8 +81,6 @@ var _ = SIGDescribe("Network", func() { } // Create a pod to check the conntrack entries on the host node - // It mounts the host /proc/net folder to be able to access - // the nf_conntrack file with the host conntrack entries privileged := true hostExecPod := &v1.Pod{ @@ -97,43 +95,17 @@ var _ = SIGDescribe("Network", func() { Containers: []v1.Container{ { Name: "e2e-net-exec", - Image: kubeProxyE2eImage, + Image: imageutils.GetE2EImage(imageutils.DebianIptables), ImagePullPolicy: v1.PullIfNotPresent, - Args: []string{"pause"}, - VolumeMounts: []v1.VolumeMount{ - { - Name: "proc-net", - MountPath: "/rootfs/proc/net", - ReadOnly: true, - }, - }, + Command: []string{"sleep", "600"}, SecurityContext: &v1.SecurityContext{ Privileged: &privileged, }, }, }, - Volumes: []v1.Volume{ - { - Name: "proc-net", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/proc/net", - }, - }, - }, - }, }, } fr.PodClient().CreateSync(hostExecPod) - defer fr.PodClient().DeleteSync(hostExecPod.Name, metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout) - - // Some distributions (Ubuntu 16.04 etc.) don't support the proc file. - _, err = framework.RunHostCmd(fr.Namespace.Name, "e2e-net-exec", - "ls /rootfs/proc/net/nf_conntrack") - if err != nil && strings.Contains(err.Error(), "No such file or directory") { - e2eskipper.Skipf("The node %s does not support /proc/net/nf_conntrack", clientNodeInfo.name) - } - framework.ExpectNoError(err) // Create the client and server pods clientPodSpec := &v1.Pod{ @@ -202,7 +174,6 @@ var _ = SIGDescribe("Network", func() { serverNodeInfo.nodeIP, kubeProxyE2eImage)) fr.PodClient().CreateSync(serverPodSpec) - defer fr.PodClient().DeleteSync(serverPodSpec.Name, metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout) // The server should be listening before spawning the client pod if readyErr := e2epod.WaitForPodsReady(fr.ClientSet, fr.Namespace.Name, serverPodSpec.Name, 0); readyErr != nil { @@ -215,22 +186,25 @@ var _ = SIGDescribe("Network", func() { clientNodeInfo.nodeIP, kubeProxyE2eImage)) fr.PodClient().CreateSync(clientPodSpec) - defer fr.PodClient().DeleteSync(clientPodSpec.Name, metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout) - ginkgo.By("Checking /proc/net/nf_conntrack for the timeout") + ginkgo.By("Checking conntrack entries for the timeout") // These must be synchronized from the default values set in // pkg/apis/../defaults.go ConntrackTCPCloseWaitTimeout. The // current defaults are hidden in the initialization code. const epsilonSeconds = 60 const expectedTimeoutSeconds = 60 * 60 // the conntrack file uses the IPv6 expanded format - ip := fullIPv6(net.ParseIP(serverNodeInfo.nodeIP)) + ip := serverNodeInfo.nodeIP + ipFamily := "ipv4" + if netutils.IsIPv6String(ip) { + ipFamily = "ipv6" + } // Obtain the corresponding conntrack entry on the host checking // the nf_conntrack file from the pod e2e-net-exec. // It retries in a loop if the entry is not found. - cmd := fmt.Sprintf("cat /rootfs/proc/net/nf_conntrack "+ - "| grep -m 1 'CLOSE_WAIT.*dst=%v.*dport=%v' ", - ip, testDaemonTCPPort) + cmd := fmt.Sprintf("conntrack -L -f %s -d %v"+ + "| grep -m 1 'CLOSE_WAIT.*dport=%v' ", + ipFamily, ip, testDaemonTCPPort) if err := wait.PollImmediate(1*time.Second, postFinTimeoutSeconds, func() (bool, error) { result, err := framework.RunHostCmd(fr.Namespace.Name, "e2e-net-exec", cmd) // retry if we can't obtain the conntrack entry @@ -239,15 +213,14 @@ var _ = SIGDescribe("Network", func() { return false, nil } framework.Logf("conntrack entry for node %v and port %v: %v", serverNodeInfo.nodeIP, testDaemonTCPPort, result) - // Timeout in seconds is available as the fifth column of - // the matched entry in /proc/net/nf_conntrack. + // Timeout in seconds is available as the third column of the matched entry line := strings.Fields(result) - if len(line) < 5 { + if len(line) < 3 { return false, fmt.Errorf("conntrack entry does not have a timeout field: %v", line) } - timeoutSeconds, err := strconv.Atoi(line[4]) + timeoutSeconds, err := strconv.Atoi(line[2]) if err != nil { - return false, fmt.Errorf("failed to convert matched timeout %s to integer: %v", line[4], err) + return false, fmt.Errorf("failed to convert matched timeout %s to integer: %v", line[2], err) } if math.Abs(float64(timeoutSeconds-expectedTimeoutSeconds)) < epsilonSeconds { return true, nil @@ -372,22 +345,3 @@ var _ = SIGDescribe("Network", func() { } }) }) - -// fullIPv6 returns a string with the IP representation -// if IPv6 it returns the expanded address format -// credit https://stackoverflow.com/a/52003106/4532704 -func fullIPv6(ip net.IP) string { - if ip.To4() == nil { - dst := make([]byte, hex.EncodedLen(len(ip))) - _ = hex.Encode(dst, ip) - return string(dst[0:4]) + ":" + - string(dst[4:8]) + ":" + - string(dst[8:12]) + ":" + - string(dst[12:16]) + ":" + - string(dst[16:20]) + ":" + - string(dst[20:24]) + ":" + - string(dst[24:28]) + ":" + - string(dst[28:]) - } - return ip.String() -} diff --git a/test/utils/image/manifest.go b/test/utils/image/manifest.go index c248758bf8b..4b77f60b3bc 100644 --- a/test/utils/image/manifest.go +++ b/test/utils/image/manifest.go @@ -32,6 +32,7 @@ type RegistryList struct { DockerGluster string `yaml:"dockerGluster"` E2eRegistry string `yaml:"e2eRegistry"` PromoterE2eRegistry string `yaml:"promoterE2eRegistry"` + BuildImageRegistry string `yaml:"buildImageRegistry"` InvalidRegistry string `yaml:"invalidRegistry"` GcRegistry string `yaml:"gcRegistry"` GcrReleaseRegistry string `yaml:"gcrReleaseRegistry"` @@ -73,6 +74,7 @@ func initReg() RegistryList { E2eRegistry: "gcr.io/kubernetes-e2e-test-images", // TODO: After the domain flip, this should instead be k8s.gcr.io/k8s-artifacts-prod/e2e-test-images PromoterE2eRegistry: "us.gcr.io/k8s-artifacts-prod/e2e-test-images", + BuildImageRegistry: "us.gcr.io/k8s-artifacts-prod/build-image", InvalidRegistry: "invalid.com/invalid", GcRegistry: "k8s.gcr.io", GcrReleaseRegistry: "gcr.io/gke-release", @@ -106,6 +108,7 @@ var ( dockerGluster = registry.DockerGluster e2eRegistry = registry.E2eRegistry promoterE2eRegistry = registry.PromoterE2eRegistry + buildImageRegistry = registry.BuildImageRegistry gcAuthenticatedRegistry = registry.GcAuthenticatedRegistry gcRegistry = registry.GcRegistry gcrReleaseRegistry = registry.GcrReleaseRegistry @@ -141,6 +144,8 @@ const ( CudaVectorAdd // CudaVectorAdd2 image CudaVectorAdd2 + // DebianIptables Image + DebianIptables // EchoServer image EchoServer // Etcd image @@ -210,6 +215,7 @@ func initImageConfigs() map[int]Config { configs[CheckMetadataConcealment] = Config{e2eRegistry, "metadata-concealment", "1.2"} configs[CudaVectorAdd] = Config{e2eRegistry, "cuda-vector-add", "1.0"} configs[CudaVectorAdd2] = Config{e2eRegistry, "cuda-vector-add", "2.0"} + configs[DebianIptables] = Config{buildImageRegistry, "debian-iptables", "v12.1.0"} configs[EchoServer] = Config{e2eRegistry, "echoserver", "2.2"} configs[Etcd] = Config{gcRegistry, "etcd", "3.4.7"} configs[GlusterDynamicProvisioner] = Config{dockerGluster, "glusterdynamic-provisioner", "v1.0"}