mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +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=
|
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"}
|
||||||
|
Loading…
Reference in New Issue
Block a user