1
16
17 package windows
18
19 import (
20 "context"
21 "fmt"
22
23 v1 "k8s.io/api/core/v1"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/apimachinery/pkg/util/uuid"
26 "k8s.io/kubernetes/test/e2e/feature"
27 "k8s.io/kubernetes/test/e2e/framework"
28 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
29 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
30 admissionapi "k8s.io/pod-security-admission/api"
31
32 imageutils "k8s.io/kubernetes/test/utils/image"
33
34 "github.com/onsi/ginkgo/v2"
35 "github.com/onsi/gomega"
36 )
37
38 const (
39 linuxOS = "linux"
40 windowsOS = "windows"
41 )
42
43 var (
44 windowsBusyBoximage = imageutils.GetE2EImage(imageutils.Agnhost)
45 linuxBusyBoxImage = imageutils.GetE2EImage(imageutils.Nginx)
46 )
47
48 var _ = sigDescribe("Hybrid cluster network", skipUnlessWindows(func() {
49 f := framework.NewDefaultFramework("hybrid-network")
50 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
51
52 ginkgo.BeforeEach(func() {
53 e2eskipper.SkipUnlessNodeOSDistroIs("windows")
54 })
55
56 ginkgo.Context("for all supported CNIs", func() {
57
58 ginkgo.It("should have stable networking for Linux and Windows pods", func(ctx context.Context) {
59
60 linuxPod := createTestPod(f, linuxBusyBoxImage, linuxOS)
61 ginkgo.By("creating a linux pod and waiting for it to be running")
62 linuxPod = e2epod.NewPodClient(f).CreateSync(ctx, linuxPod)
63
64 windowsPod := createTestPod(f, windowsBusyBoximage, windowsOS)
65
66 windowsPod.Spec.Containers[0].Args = []string{"test-webserver"}
67 ginkgo.By("creating a windows pod and waiting for it to be running")
68 windowsPod = e2epod.NewPodClient(f).CreateSync(ctx, windowsPod)
69
70 ginkgo.By("verifying pod internal connectivity to the cluster dataplane")
71
72 ginkgo.By("checking connectivity from Linux to Windows")
73 assertConsistentConnectivity(ctx, f, linuxPod.ObjectMeta.Name, linuxOS, linuxCheck(windowsPod.Status.PodIP, 80), internalMaxTries)
74
75 ginkgo.By("checking connectivity from Windows to Linux")
76 assertConsistentConnectivity(ctx, f, windowsPod.ObjectMeta.Name, windowsOS, windowsCheck(linuxPod.Status.PodIP), internalMaxTries)
77
78 })
79
80 f.It("should provide Internet connection for Linux containers using DNS", feature.NetworkingDNS, func(ctx context.Context) {
81 linuxPod := createTestPod(f, linuxBusyBoxImage, linuxOS)
82 ginkgo.By("creating a linux pod and waiting for it to be running")
83 linuxPod = e2epod.NewPodClient(f).CreateSync(ctx, linuxPod)
84
85 ginkgo.By("verifying pod external connectivity to the internet")
86
87 ginkgo.By("checking connectivity to 8.8.8.8 53 (google.com) from Linux")
88 assertConsistentConnectivity(ctx, f, linuxPod.ObjectMeta.Name, linuxOS, linuxCheck("8.8.8.8", 53), externalMaxTries)
89 })
90
91 f.It("should provide Internet connection for Windows containers using DNS", feature.NetworkingDNS, func(ctx context.Context) {
92 windowsPod := createTestPod(f, windowsBusyBoximage, windowsOS)
93 ginkgo.By("creating a windows pod and waiting for it to be running")
94 windowsPod = e2epod.NewPodClient(f).CreateSync(ctx, windowsPod)
95
96 ginkgo.By("verifying pod external connectivity to the internet")
97
98 ginkgo.By("checking connectivity to 8.8.8.8 53 (google.com) from Windows")
99 assertConsistentConnectivity(ctx, f, windowsPod.ObjectMeta.Name, windowsOS, windowsCheck("www.google.com"), externalMaxTries)
100 })
101
102 })
103 }))
104
105 var (
106 warmUpDuration = "30s"
107 duration = "10s"
108 pollInterval = "1s"
109 timeoutSeconds = 10
110
111 externalMaxTries = 10
112 internalMaxTries = 1
113 )
114
115 func assertConsistentConnectivity(ctx context.Context, f *framework.Framework, podName string, os string, cmd []string, maxTries int) {
116 connChecker := func() error {
117 var err error
118 for i := 0; i < maxTries; i++ {
119 ginkgo.By(fmt.Sprintf("checking connectivity of %s-container in %s", os, podName))
120 stdout, stderr, err := e2epod.ExecCommandInContainerWithFullOutput(f, podName, os+"-container", cmd...)
121 if err == nil {
122 break
123 }
124 framework.Logf("Encountered error while running command: %v.\nStdout: %s\nStderr: %s\nErr: %v", cmd, stdout, stderr, err)
125 }
126 return err
127 }
128 gomega.Eventually(ctx, connChecker, warmUpDuration, pollInterval).ShouldNot(gomega.HaveOccurred())
129 gomega.Consistently(ctx, connChecker, duration, pollInterval).ShouldNot(gomega.HaveOccurred())
130 }
131
132 func linuxCheck(address string, port int) []string {
133 nc := fmt.Sprintf("nc -vz %s %v -w %v", address, port, timeoutSeconds)
134 cmd := []string{"/bin/sh", "-c", nc}
135 return cmd
136 }
137
138 func windowsCheck(address string) []string {
139 curl := fmt.Sprintf("curl.exe %s --connect-timeout %v --fail", address, timeoutSeconds)
140 cmd := []string{"cmd", "/c", curl}
141 return cmd
142 }
143
144 func createTestPod(f *framework.Framework, image string, os string) *v1.Pod {
145 containerName := fmt.Sprintf("%s-container", os)
146 podName := "pod-" + string(uuid.NewUUID())
147 pod := &v1.Pod{
148 TypeMeta: metav1.TypeMeta{
149 Kind: "Pod",
150 APIVersion: "v1",
151 },
152 ObjectMeta: metav1.ObjectMeta{
153 Name: podName,
154 },
155 Spec: v1.PodSpec{
156 Containers: []v1.Container{
157 {
158 Name: containerName,
159 Image: image,
160 Ports: []v1.ContainerPort{{ContainerPort: 80}},
161 },
162 },
163 NodeSelector: map[string]string{
164 "kubernetes.io/os": os,
165 },
166 },
167 }
168 if os == linuxOS {
169 pod.Spec.Tolerations = []v1.Toleration{
170 {
171 Operator: v1.TolerationOpExists,
172 Effect: v1.TaintEffectNoSchedule,
173 },
174 }
175 }
176 return pod
177 }
178
View as plain text