mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #90687 from aojea/connt
use conntrack instead of the /proc file for the e2e test TCP CLOSE_WAIT
This commit is contained in:
		@@ -116,6 +116,8 @@ dependencies:
 | 
				
			|||||||
      match: debian_iptables_version=
 | 
					      match: debian_iptables_version=
 | 
				
			||||||
    - path: build/workspace.bzl
 | 
					    - path: build/workspace.bzl
 | 
				
			||||||
      match: tag =
 | 
					      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"
 | 
					  - name: "k8s.gcr.io/go-runner"
 | 
				
			||||||
    version: 0.1.1
 | 
					    version: 0.1.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ package network
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/hex"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"math"
 | 
						"math"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
@@ -35,6 +34,7 @@ import (
 | 
				
			|||||||
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
 | 
						e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
 | 
				
			||||||
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
 | 
						e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
 | 
				
			||||||
	imageutils "k8s.io/kubernetes/test/utils/image"
 | 
						imageutils "k8s.io/kubernetes/test/utils/image"
 | 
				
			||||||
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/onsi/ginkgo"
 | 
						"github.com/onsi/ginkgo"
 | 
				
			||||||
	"github.com/onsi/gomega"
 | 
						"github.com/onsi/gomega"
 | 
				
			||||||
@@ -81,8 +81,6 @@ var _ = SIGDescribe("Network", func() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Create a pod to check the conntrack entries on the host node
 | 
							// 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
 | 
							privileged := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hostExecPod := &v1.Pod{
 | 
							hostExecPod := &v1.Pod{
 | 
				
			||||||
@@ -97,43 +95,17 @@ var _ = SIGDescribe("Network", func() {
 | 
				
			|||||||
				Containers: []v1.Container{
 | 
									Containers: []v1.Container{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Name:            "e2e-net-exec",
 | 
											Name:            "e2e-net-exec",
 | 
				
			||||||
						Image:           kubeProxyE2eImage,
 | 
											Image:           imageutils.GetE2EImage(imageutils.DebianIptables),
 | 
				
			||||||
						ImagePullPolicy: v1.PullIfNotPresent,
 | 
											ImagePullPolicy: v1.PullIfNotPresent,
 | 
				
			||||||
						Args:            []string{"pause"},
 | 
											Command:         []string{"sleep", "600"},
 | 
				
			||||||
						VolumeMounts: []v1.VolumeMount{
 | 
					 | 
				
			||||||
							{
 | 
					 | 
				
			||||||
								Name:      "proc-net",
 | 
					 | 
				
			||||||
								MountPath: "/rootfs/proc/net",
 | 
					 | 
				
			||||||
								ReadOnly:  true,
 | 
					 | 
				
			||||||
							},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
						SecurityContext: &v1.SecurityContext{
 | 
											SecurityContext: &v1.SecurityContext{
 | 
				
			||||||
							Privileged: &privileged,
 | 
												Privileged: &privileged,
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Volumes: []v1.Volume{
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						Name: "proc-net",
 | 
					 | 
				
			||||||
						VolumeSource: v1.VolumeSource{
 | 
					 | 
				
			||||||
							HostPath: &v1.HostPathVolumeSource{
 | 
					 | 
				
			||||||
								Path: "/proc/net",
 | 
					 | 
				
			||||||
							},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fr.PodClient().CreateSync(hostExecPod)
 | 
							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
 | 
							// Create the client and server pods
 | 
				
			||||||
		clientPodSpec := &v1.Pod{
 | 
							clientPodSpec := &v1.Pod{
 | 
				
			||||||
@@ -202,7 +174,6 @@ var _ = SIGDescribe("Network", func() {
 | 
				
			|||||||
			serverNodeInfo.nodeIP,
 | 
								serverNodeInfo.nodeIP,
 | 
				
			||||||
			kubeProxyE2eImage))
 | 
								kubeProxyE2eImage))
 | 
				
			||||||
		fr.PodClient().CreateSync(serverPodSpec)
 | 
							fr.PodClient().CreateSync(serverPodSpec)
 | 
				
			||||||
		defer fr.PodClient().DeleteSync(serverPodSpec.Name, metav1.DeleteOptions{}, framework.DefaultPodDeletionTimeout)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The server should be listening before spawning the client pod
 | 
							// The server should be listening before spawning the client pod
 | 
				
			||||||
		if readyErr := e2epod.WaitForPodsReady(fr.ClientSet, fr.Namespace.Name, serverPodSpec.Name, 0); readyErr != nil {
 | 
							if readyErr := e2epod.WaitForPodsReady(fr.ClientSet, fr.Namespace.Name, serverPodSpec.Name, 0); readyErr != nil {
 | 
				
			||||||
@@ -215,22 +186,25 @@ var _ = SIGDescribe("Network", func() {
 | 
				
			|||||||
			clientNodeInfo.nodeIP,
 | 
								clientNodeInfo.nodeIP,
 | 
				
			||||||
			kubeProxyE2eImage))
 | 
								kubeProxyE2eImage))
 | 
				
			||||||
		fr.PodClient().CreateSync(clientPodSpec)
 | 
							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
 | 
							// These must be synchronized from the default values set in
 | 
				
			||||||
		// pkg/apis/../defaults.go ConntrackTCPCloseWaitTimeout. The
 | 
							// pkg/apis/../defaults.go ConntrackTCPCloseWaitTimeout. The
 | 
				
			||||||
		// current defaults are hidden in the initialization code.
 | 
							// current defaults are hidden in the initialization code.
 | 
				
			||||||
		const epsilonSeconds = 60
 | 
							const epsilonSeconds = 60
 | 
				
			||||||
		const expectedTimeoutSeconds = 60 * 60
 | 
							const expectedTimeoutSeconds = 60 * 60
 | 
				
			||||||
		// the conntrack file uses the IPv6 expanded format
 | 
							// 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
 | 
							// Obtain the corresponding conntrack entry on the host checking
 | 
				
			||||||
		// the nf_conntrack file from the pod e2e-net-exec.
 | 
							// the nf_conntrack file from the pod e2e-net-exec.
 | 
				
			||||||
		// It retries in a loop if the entry is not found.
 | 
							// It retries in a loop if the entry is not found.
 | 
				
			||||||
		cmd := fmt.Sprintf("cat /rootfs/proc/net/nf_conntrack "+
 | 
							cmd := fmt.Sprintf("conntrack -L -f %s -d %v"+
 | 
				
			||||||
			"| grep -m 1 'CLOSE_WAIT.*dst=%v.*dport=%v' ",
 | 
								"| grep -m 1 'CLOSE_WAIT.*dport=%v' ",
 | 
				
			||||||
			ip, testDaemonTCPPort)
 | 
								ipFamily, ip, testDaemonTCPPort)
 | 
				
			||||||
		if err := wait.PollImmediate(1*time.Second, postFinTimeoutSeconds, func() (bool, error) {
 | 
							if err := wait.PollImmediate(1*time.Second, postFinTimeoutSeconds, func() (bool, error) {
 | 
				
			||||||
			result, err := framework.RunHostCmd(fr.Namespace.Name, "e2e-net-exec", cmd)
 | 
								result, err := framework.RunHostCmd(fr.Namespace.Name, "e2e-net-exec", cmd)
 | 
				
			||||||
			// retry if we can't obtain the conntrack entry
 | 
								// retry if we can't obtain the conntrack entry
 | 
				
			||||||
@@ -239,15 +213,14 @@ var _ = SIGDescribe("Network", func() {
 | 
				
			|||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			framework.Logf("conntrack entry for node %v and port %v:  %v", serverNodeInfo.nodeIP, testDaemonTCPPort, result)
 | 
								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
 | 
								// Timeout in seconds is available as the third column of the matched entry
 | 
				
			||||||
			// the matched entry in /proc/net/nf_conntrack.
 | 
					 | 
				
			||||||
			line := strings.Fields(result)
 | 
								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)
 | 
									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 {
 | 
								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 {
 | 
								if math.Abs(float64(timeoutSeconds-expectedTimeoutSeconds)) < epsilonSeconds {
 | 
				
			||||||
				return true, nil
 | 
									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()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ type RegistryList struct {
 | 
				
			|||||||
	DockerGluster           string `yaml:"dockerGluster"`
 | 
						DockerGluster           string `yaml:"dockerGluster"`
 | 
				
			||||||
	E2eRegistry             string `yaml:"e2eRegistry"`
 | 
						E2eRegistry             string `yaml:"e2eRegistry"`
 | 
				
			||||||
	PromoterE2eRegistry     string `yaml:"promoterE2eRegistry"`
 | 
						PromoterE2eRegistry     string `yaml:"promoterE2eRegistry"`
 | 
				
			||||||
 | 
						BuildImageRegistry      string `yaml:"buildImageRegistry"`
 | 
				
			||||||
	InvalidRegistry         string `yaml:"invalidRegistry"`
 | 
						InvalidRegistry         string `yaml:"invalidRegistry"`
 | 
				
			||||||
	GcRegistry              string `yaml:"gcRegistry"`
 | 
						GcRegistry              string `yaml:"gcRegistry"`
 | 
				
			||||||
	GcrReleaseRegistry      string `yaml:"gcrReleaseRegistry"`
 | 
						GcrReleaseRegistry      string `yaml:"gcrReleaseRegistry"`
 | 
				
			||||||
@@ -73,6 +74,7 @@ func initReg() RegistryList {
 | 
				
			|||||||
		E2eRegistry:             "gcr.io/kubernetes-e2e-test-images",
 | 
							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
 | 
							// 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",
 | 
							PromoterE2eRegistry: "us.gcr.io/k8s-artifacts-prod/e2e-test-images",
 | 
				
			||||||
 | 
							BuildImageRegistry:  "us.gcr.io/k8s-artifacts-prod/build-image",
 | 
				
			||||||
		InvalidRegistry:     "invalid.com/invalid",
 | 
							InvalidRegistry:     "invalid.com/invalid",
 | 
				
			||||||
		GcRegistry:          "k8s.gcr.io",
 | 
							GcRegistry:          "k8s.gcr.io",
 | 
				
			||||||
		GcrReleaseRegistry:  "gcr.io/gke-release",
 | 
							GcrReleaseRegistry:  "gcr.io/gke-release",
 | 
				
			||||||
@@ -106,6 +108,7 @@ var (
 | 
				
			|||||||
	dockerGluster           = registry.DockerGluster
 | 
						dockerGluster           = registry.DockerGluster
 | 
				
			||||||
	e2eRegistry             = registry.E2eRegistry
 | 
						e2eRegistry             = registry.E2eRegistry
 | 
				
			||||||
	promoterE2eRegistry     = registry.PromoterE2eRegistry
 | 
						promoterE2eRegistry     = registry.PromoterE2eRegistry
 | 
				
			||||||
 | 
						buildImageRegistry      = registry.BuildImageRegistry
 | 
				
			||||||
	gcAuthenticatedRegistry = registry.GcAuthenticatedRegistry
 | 
						gcAuthenticatedRegistry = registry.GcAuthenticatedRegistry
 | 
				
			||||||
	gcRegistry              = registry.GcRegistry
 | 
						gcRegistry              = registry.GcRegistry
 | 
				
			||||||
	gcrReleaseRegistry      = registry.GcrReleaseRegistry
 | 
						gcrReleaseRegistry      = registry.GcrReleaseRegistry
 | 
				
			||||||
@@ -141,6 +144,8 @@ const (
 | 
				
			|||||||
	CudaVectorAdd
 | 
						CudaVectorAdd
 | 
				
			||||||
	// CudaVectorAdd2 image
 | 
						// CudaVectorAdd2 image
 | 
				
			||||||
	CudaVectorAdd2
 | 
						CudaVectorAdd2
 | 
				
			||||||
 | 
						// DebianIptables Image
 | 
				
			||||||
 | 
						DebianIptables
 | 
				
			||||||
	// EchoServer image
 | 
						// EchoServer image
 | 
				
			||||||
	EchoServer
 | 
						EchoServer
 | 
				
			||||||
	// Etcd image
 | 
						// Etcd image
 | 
				
			||||||
@@ -210,6 +215,7 @@ func initImageConfigs() map[int]Config {
 | 
				
			|||||||
	configs[CheckMetadataConcealment] = Config{e2eRegistry, "metadata-concealment", "1.2"}
 | 
						configs[CheckMetadataConcealment] = Config{e2eRegistry, "metadata-concealment", "1.2"}
 | 
				
			||||||
	configs[CudaVectorAdd] = Config{e2eRegistry, "cuda-vector-add", "1.0"}
 | 
						configs[CudaVectorAdd] = Config{e2eRegistry, "cuda-vector-add", "1.0"}
 | 
				
			||||||
	configs[CudaVectorAdd2] = Config{e2eRegistry, "cuda-vector-add", "2.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[EchoServer] = Config{e2eRegistry, "echoserver", "2.2"}
 | 
				
			||||||
	configs[Etcd] = Config{gcRegistry, "etcd", "3.4.7"}
 | 
						configs[Etcd] = Config{gcRegistry, "etcd", "3.4.7"}
 | 
				
			||||||
	configs[GlusterDynamicProvisioner] = Config{dockerGluster, "glusterdynamic-provisioner", "v1.0"}
 | 
						configs[GlusterDynamicProvisioner] = Config{dockerGluster, "glusterdynamic-provisioner", "v1.0"}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user