mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +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:
commit
7937aa60a3
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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"}
|
||||
|
Loading…
Reference in New Issue
Block a user