1
16
17 package network
18
19 import (
20 "context"
21 "fmt"
22 "strings"
23 "time"
24
25 v1 "k8s.io/api/core/v1"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/util/wait"
28 "k8s.io/kubernetes/test/e2e/framework"
29 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
30 e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
31 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
32 "k8s.io/kubernetes/test/e2e/network/common"
33 admissionapi "k8s.io/pod-security-admission/api"
34
35 "github.com/onsi/ginkgo/v2"
36 )
37
38 const dnsTestPodHostName = "dns-querier-1"
39 const dnsTestServiceName = "dns-test-service"
40
41 var _ = common.SIGDescribe("DNS", func() {
42 f := framework.NewDefaultFramework("dns")
43 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
44
45
50 framework.ConformanceIt("should provide DNS for the cluster", func(ctx context.Context) {
51
52
53
54 namesToResolve := []string{
55 fmt.Sprintf("kubernetes.default.svc.%s", framework.TestContext.ClusterDNSDomain),
56 }
57
58 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
59 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
60 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
61 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
62
63
64 ginkgo.By("creating a pod to probe DNS")
65 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
66 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
67 })
68
69
70 ginkgo.It("should provide DNS for the cluster [Provider:GCE]", func(ctx context.Context) {
71 e2eskipper.SkipUnlessProviderIs("gce", "gke")
72
73 namesToResolve := []string{"google.com"}
74
75 if !framework.NodeOSDistroIs("windows") {
76 namesToResolve = append(namesToResolve, "metadata")
77 }
78
79
80 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
81 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
82 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
83 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
84
85
86 ginkgo.By("creating a pod to probe DNS")
87 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
88 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
89 })
90
91
92 ginkgo.It("should resolve DNS of partial qualified names for the cluster [LinuxOnly]", func(ctx context.Context) {
93
94 namesToResolve := []string{
95 "kubernetes.default",
96 "kubernetes.default.svc",
97 }
98 hostFQDN := fmt.Sprintf("%s.%s.%s.svc.%s", dnsTestPodHostName, dnsTestServiceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
99 hostEntries := []string{hostFQDN, dnsTestPodHostName}
100
101 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostEntries, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
102 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostEntries, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
103 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
104 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
105
106
107 ginkgo.By("creating a pod to probe DNS")
108 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
109 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
110 })
111
112
117 framework.ConformanceIt("should provide /etc/hosts entries for the cluster", func(ctx context.Context) {
118 hostFQDN := fmt.Sprintf("%s.%s.%s.svc.%s", dnsTestPodHostName, dnsTestServiceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
119 hostEntries := []string{hostFQDN, dnsTestPodHostName}
120
121 wheezyProbeCmd, wheezyFileNames := createProbeCommand(nil, hostEntries, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
122 jessieProbeCmd, jessieFileNames := createProbeCommand(nil, hostEntries, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
123 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
124 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
125
126
127 ginkgo.By("creating a pod to probe /etc/hosts")
128 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
129 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
130 })
131
132
137 framework.ConformanceIt("should provide DNS for services", func(ctx context.Context) {
138
139
140 ginkgo.By("Creating a test headless service")
141 testServiceSelector := map[string]string{
142 "dns-test": "true",
143 }
144 headlessService := e2eservice.CreateServiceSpec(dnsTestServiceName, "", true, testServiceSelector)
145 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, headlessService, metav1.CreateOptions{})
146 framework.ExpectNoError(err, "failed to create headless service: %s", dnsTestServiceName)
147 ginkgo.DeferCleanup(func(ctx context.Context) error {
148 ginkgo.By("deleting the test headless service")
149 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, headlessService.Name, metav1.DeleteOptions{})
150 })
151
152 regularServiceName := "test-service-2"
153 regularService := e2eservice.CreateServiceSpec(regularServiceName, "", false, testServiceSelector)
154 regularService, err = f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, regularService, metav1.CreateOptions{})
155 framework.ExpectNoError(err, "failed to create regular service: %s", regularServiceName)
156
157 ginkgo.DeferCleanup(func(ctx context.Context) error {
158 ginkgo.By("deleting the test service")
159 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, regularService.Name, metav1.DeleteOptions{})
160 })
161
162
163
164
165 namesToResolve := []string{
166 fmt.Sprintf("%s.%s.svc.%s", headlessService.Name, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
167 fmt.Sprintf("_http._tcp.%s.%s.svc.%s", headlessService.Name, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
168 fmt.Sprintf("_http._tcp.%s.%s.svc.%s", regularService.Name, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
169 }
170
171
172 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
173 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
174 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
175 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
176
177
178 ginkgo.By("creating a pod to probe DNS")
179 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
180 pod.ObjectMeta.Labels = testServiceSelector
181
182 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
183 })
184
185
191 framework.ConformanceIt("should resolve DNS of partial qualified names for services [LinuxOnly]", func(ctx context.Context) {
192
193 ginkgo.By("Creating a test headless service")
194 testServiceSelector := map[string]string{
195 "dns-test": "true",
196 }
197 headlessService := e2eservice.CreateServiceSpec(dnsTestServiceName, "", true, testServiceSelector)
198 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, headlessService, metav1.CreateOptions{})
199 framework.ExpectNoError(err, "failed to create headless service: %s", dnsTestServiceName)
200 ginkgo.DeferCleanup(func(ctx context.Context) error {
201 ginkgo.By("deleting the test headless service")
202 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, headlessService.Name, metav1.DeleteOptions{})
203 })
204
205 regularServiceName := "test-service-2"
206 regularService := e2eservice.CreateServiceSpec(regularServiceName, "", false, testServiceSelector)
207 regularService, err = f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, regularService, metav1.CreateOptions{})
208 framework.ExpectNoError(err, "failed to create regular service: %s", regularServiceName)
209 ginkgo.DeferCleanup(func(ctx context.Context) error {
210 ginkgo.By("deleting the test service")
211 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, regularService.Name, metav1.DeleteOptions{})
212 })
213
214
215
216 namesToResolve := []string{
217 headlessService.Name,
218 fmt.Sprintf("%s.%s", headlessService.Name, f.Namespace.Name),
219 fmt.Sprintf("%s.%s.svc", headlessService.Name, f.Namespace.Name),
220 fmt.Sprintf("_http._tcp.%s.%s.svc", headlessService.Name, f.Namespace.Name),
221 fmt.Sprintf("_http._tcp.%s.%s.svc", regularService.Name, f.Namespace.Name),
222 }
223
224
225 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
226 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
227 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
228 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
229
230
231 ginkgo.By("creating a pod to probe DNS")
232 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
233 pod.ObjectMeta.Labels = testServiceSelector
234
235 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
236 })
237
238
244 framework.ConformanceIt("should provide DNS for pods for Hostname", func(ctx context.Context) {
245
246 ginkgo.By("Creating a test headless service")
247 testServiceSelector := map[string]string{
248 "dns-test-hostname-attribute": "true",
249 }
250 serviceName := "dns-test-service-2"
251 podHostname := "dns-querier-2"
252 headlessService := e2eservice.CreateServiceSpec(serviceName, "", true, testServiceSelector)
253 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, headlessService, metav1.CreateOptions{})
254 framework.ExpectNoError(err, "failed to create headless service: %s", serviceName)
255
256 ginkgo.DeferCleanup(func(ctx context.Context) error {
257 ginkgo.By("deleting the test headless service")
258 defer ginkgo.GinkgoRecover()
259 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, headlessService.Name, metav1.DeleteOptions{})
260 })
261
262 hostFQDN := fmt.Sprintf("%s.%s.%s.svc.%s", podHostname, serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
263 hostNames := []string{hostFQDN, podHostname}
264
265 wheezyProbeCmd, wheezyFileNames := createProbeCommand(nil, hostNames, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
266 jessieProbeCmd, jessieFileNames := createProbeCommand(nil, hostNames, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
267 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
268 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
269
270
271 ginkgo.By("creating a pod to probe DNS")
272 pod1 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
273 pod1.ObjectMeta.Labels = testServiceSelector
274 pod1.Spec.Hostname = podHostname
275 pod1.Spec.Subdomain = serviceName
276
277 validateDNSResults(ctx, f, pod1, append(wheezyFileNames, jessieFileNames...))
278 })
279
280
286 framework.ConformanceIt("should provide DNS for pods for Subdomain", func(ctx context.Context) {
287
288 ginkgo.By("Creating a test headless service")
289 testServiceSelector := map[string]string{
290 "dns-test-hostname-attribute": "true",
291 }
292 serviceName := "dns-test-service-2"
293 podHostname := "dns-querier-2"
294 headlessService := e2eservice.CreateServiceSpec(serviceName, "", true, testServiceSelector)
295 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, headlessService, metav1.CreateOptions{})
296 framework.ExpectNoError(err, "failed to create headless service: %s", serviceName)
297
298 ginkgo.DeferCleanup(func(ctx context.Context) error {
299 ginkgo.By("deleting the test headless service")
300 defer ginkgo.GinkgoRecover()
301 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, headlessService.Name, metav1.DeleteOptions{})
302 })
303
304 hostFQDN := fmt.Sprintf("%s.%s.%s.svc.%s", podHostname, serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
305 subdomain := fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
306 namesToResolve := []string{hostFQDN, subdomain}
307
308 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
309 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
310 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
311 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
312
313
314 ginkgo.By("creating a pod to probe DNS")
315 pod1 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
316 pod1.ObjectMeta.Labels = testServiceSelector
317 pod1.Spec.Hostname = podHostname
318 pod1.Spec.Subdomain = serviceName
319
320 validateDNSResults(ctx, f, pod1, append(wheezyFileNames, jessieFileNames...))
321 })
322
323
329 framework.ConformanceIt("should provide DNS for ExternalName services", func(ctx context.Context) {
330
331 ginkgo.By("Creating a test externalName service")
332 serviceName := "dns-test-service-3"
333 externalNameService := e2eservice.CreateServiceSpec(serviceName, "foo.example.com", false, nil)
334 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, externalNameService, metav1.CreateOptions{})
335 framework.ExpectNoError(err, "failed to create ExternalName service: %s", serviceName)
336
337 ginkgo.DeferCleanup(func(ctx context.Context) error {
338 ginkgo.By("deleting the test externalName service")
339 defer ginkgo.GinkgoRecover()
340 return f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(ctx, externalNameService.Name, metav1.DeleteOptions{})
341 })
342 hostFQDN := fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
343 wheezyProbeCmd, wheezyFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy")
344 jessieProbeCmd, jessieFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "jessie")
345 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
346 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
347
348
349 ginkgo.By("creating a pod to probe DNS")
350 pod1 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
351
352 validateTargetedProbeOutput(ctx, f, pod1, []string{wheezyFileName, jessieFileName}, "foo.example.com.")
353
354
355 ginkgo.By("changing the externalName to bar.example.com")
356 _, err = e2eservice.UpdateService(ctx, f.ClientSet, f.Namespace.Name, serviceName, func(s *v1.Service) {
357 s.Spec.ExternalName = "bar.example.com"
358 })
359 framework.ExpectNoError(err, "failed to change externalName of service: %s", serviceName)
360 wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy")
361 jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "jessie")
362 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
363 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
364
365
366 ginkgo.By("creating a second pod to probe DNS")
367 pod2 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
368
369 validateTargetedProbeOutput(ctx, f, pod2, []string{wheezyFileName, jessieFileName}, "bar.example.com.")
370
371
372 ginkgo.By("changing the service to type=ClusterIP")
373 _, err = e2eservice.UpdateService(ctx, f.ClientSet, f.Namespace.Name, serviceName, func(s *v1.Service) {
374 s.Spec.Type = v1.ServiceTypeClusterIP
375 s.Spec.Ports = []v1.ServicePort{
376 {Port: 80, Name: "http", Protocol: v1.ProtocolTCP},
377 }
378 })
379 framework.ExpectNoError(err, "failed to change service type to ClusterIP for service: %s", serviceName)
380 targetRecord := "A"
381 if framework.TestContext.ClusterIsIPv6() {
382 targetRecord = "AAAA"
383 }
384
385
386 wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, targetRecord, "wheezy")
387 jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, targetRecord, "jessie")
388 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
389 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
390
391
392 ginkgo.By("creating a third pod to probe DNS")
393 pod3 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
394
395 svc, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Get(ctx, externalNameService.Name, metav1.GetOptions{})
396 framework.ExpectNoError(err, "failed to get service: %s", externalNameService.Name)
397
398 validateTargetedProbeOutput(ctx, f, pod3, []string{wheezyFileName, jessieFileName}, svc.Spec.ClusterIP)
399 })
400
401
407 framework.ConformanceIt("should support configurable pod DNS nameservers", func(ctx context.Context) {
408 ginkgo.By("Creating a pod with dnsPolicy=None and customized dnsConfig...")
409 testServerIP := "1.1.1.1"
410 testSearchPath := "resolv.conf.local"
411 testAgnhostPod := e2epod.NewAgnhostPod(f.Namespace.Name, "test-dns-nameservers", nil, nil, nil)
412 testAgnhostPod.Spec.DNSPolicy = v1.DNSNone
413 testAgnhostPod.Spec.DNSConfig = &v1.PodDNSConfig{
414 Nameservers: []string{testServerIP},
415 Searches: []string{testSearchPath},
416 }
417 testAgnhostPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(ctx, testAgnhostPod, metav1.CreateOptions{})
418 framework.ExpectNoError(err, "failed to create pod: %s", testAgnhostPod.Name)
419 framework.Logf("Created pod %v", testAgnhostPod)
420 ginkgo.DeferCleanup(func(ctx context.Context) error {
421 framework.Logf("Deleting pod %s...", testAgnhostPod.Name)
422 return f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(ctx, testAgnhostPod.Name, *metav1.NewDeleteOptions(0))
423 })
424 err = e2epod.WaitTimeoutForPodReadyInNamespace(ctx, f.ClientSet, testAgnhostPod.Name, f.Namespace.Name, framework.PodStartTimeout)
425 framework.ExpectNoError(err, "failed to wait for pod %s to be running", testAgnhostPod.Name)
426
427 runCommand := func(arg string) string {
428 cmd := []string{"/agnhost", arg}
429 stdout, stderr, err := e2epod.ExecWithOptions(f, e2epod.ExecOptions{
430 Command: cmd,
431 Namespace: f.Namespace.Name,
432 PodName: testAgnhostPod.Name,
433 ContainerName: testAgnhostPod.Spec.Containers[0].Name,
434 CaptureStdout: true,
435 CaptureStderr: true,
436 })
437 framework.ExpectNoError(err, "failed to run command '/agnhost %s' on pod, stdout: %v, stderr: %v, err: %v", arg, stdout, stderr, err)
438 return stdout
439 }
440
441 ginkgo.By("Verifying customized DNS suffix list is configured on pod...")
442 stdout := runCommand("dns-suffix")
443 if !strings.Contains(stdout, testSearchPath) {
444 framework.Failf("customized DNS suffix list not found configured in pod, expected to contain: %s, got: %s", testSearchPath, stdout)
445 }
446
447 ginkgo.By("Verifying customized DNS server is configured on pod...")
448 stdout = runCommand("dns-server-list")
449 if !strings.Contains(stdout, testServerIP) {
450 framework.Failf("customized DNS server not found in configured in pod, expected to contain: %s, got: %s", testServerIP, stdout)
451 }
452 })
453
454 ginkgo.It("should support configurable pod resolv.conf", func(ctx context.Context) {
455 ginkgo.By("Preparing a test DNS service with injected DNS names...")
456 testInjectedIP := "1.1.1.1"
457 testDNSNameShort := "notexistname"
458 testSearchPath := "resolv.conf.local"
459 testDNSNameFull := fmt.Sprintf("%s.%s", testDNSNameShort, testSearchPath)
460
461 corednsConfig := generateCoreDNSConfigmap(f.Namespace.Name, map[string]string{
462 testDNSNameFull: testInjectedIP,
463 })
464 corednsConfig, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, corednsConfig, metav1.CreateOptions{})
465 framework.ExpectNoError(err, "unable to create test configMap %s", corednsConfig.Name)
466
467 ginkgo.DeferCleanup(func(ctx context.Context) error {
468 framework.Logf("Deleting configmap %s...", corednsConfig.Name)
469 return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(ctx, corednsConfig.Name, metav1.DeleteOptions{})
470 })
471
472 testServerPod := generateCoreDNSServerPod(corednsConfig)
473 testServerPod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(ctx, testServerPod, metav1.CreateOptions{})
474 framework.ExpectNoError(err, "failed to create pod: %s", testServerPod.Name)
475 framework.Logf("Created pod %v", testServerPod)
476 ginkgo.DeferCleanup(func(ctx context.Context) error {
477 framework.Logf("Deleting pod %s...", testServerPod.Name)
478 return f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(ctx, testServerPod.Name, *metav1.NewDeleteOptions(0))
479 })
480 err = e2epod.WaitForPodNameRunningInNamespace(ctx, f.ClientSet, testServerPod.Name, f.Namespace.Name)
481 framework.ExpectNoError(err, "failed to wait for pod %s to be running", testServerPod.Name)
482
483
484 testServerPod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(ctx, testServerPod.Name, metav1.GetOptions{})
485 framework.ExpectNoError(err, "failed to get pod %v", testServerPod.Name)
486 testServerIP := testServerPod.Status.PodIP
487 framework.Logf("testServerIP is %s", testServerIP)
488
489 ginkgo.By("Creating a pod with dnsPolicy=None and customized dnsConfig...")
490 testUtilsPod := e2epod.NewAgnhostPod(f.Namespace.Name, "e2e-dns-utils", nil, nil, nil)
491 testUtilsPod.Spec.DNSPolicy = v1.DNSNone
492 testNdotsValue := "2"
493 testUtilsPod.Spec.DNSConfig = &v1.PodDNSConfig{
494 Nameservers: []string{testServerIP},
495 Searches: []string{testSearchPath},
496 Options: []v1.PodDNSConfigOption{
497 {
498 Name: "ndots",
499 Value: &testNdotsValue,
500 },
501 },
502 }
503 testUtilsPod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(ctx, testUtilsPod, metav1.CreateOptions{})
504 framework.ExpectNoError(err, "failed to create pod: %s", testUtilsPod.Name)
505 framework.Logf("Created pod %v", testUtilsPod)
506 ginkgo.DeferCleanup(func(ctx context.Context) error {
507 framework.Logf("Deleting pod %s...", testUtilsPod.Name)
508 return f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(ctx, testUtilsPod.Name, *metav1.NewDeleteOptions(0))
509 })
510 err = e2epod.WaitForPodNameRunningInNamespace(ctx, f.ClientSet, testUtilsPod.Name, f.Namespace.Name)
511 framework.ExpectNoError(err, "failed to wait for pod %s to be running", testUtilsPod.Name)
512
513 ginkgo.By("Verifying customized DNS option is configured on pod...")
514
515 cmd := []string{"cat", "/etc/resolv.conf"}
516 stdout, stderr, err := e2epod.ExecWithOptions(f, e2epod.ExecOptions{
517 Command: cmd,
518 Namespace: f.Namespace.Name,
519 PodName: testUtilsPod.Name,
520 ContainerName: testUtilsPod.Spec.Containers[0].Name,
521 CaptureStdout: true,
522 CaptureStderr: true,
523 })
524 framework.ExpectNoError(err, "failed to examine resolv,conf file on pod, stdout: %v, stderr: %v, err: %v", stdout, stderr, err)
525 if !strings.Contains(stdout, "ndots:2") {
526 framework.Failf("customized DNS options not found in resolv.conf, got: %s", stdout)
527 }
528
529 ginkgo.By("Verifying customized name server and search path are working...")
530
531
532
533
534 cmd = []string{"dig", "+short", "+search", testDNSNameShort}
535 digFunc := func() (bool, error) {
536 stdout, stderr, err := e2epod.ExecWithOptions(f, e2epod.ExecOptions{
537 Command: cmd,
538 Namespace: f.Namespace.Name,
539 PodName: testUtilsPod.Name,
540 ContainerName: testUtilsPod.Spec.Containers[0].Name,
541 CaptureStdout: true,
542 CaptureStderr: true,
543 })
544 if err != nil {
545 framework.Logf("ginkgo.Failed to execute dig command, stdout:%v, stderr: %v, err: %v", stdout, stderr, err)
546 return false, nil
547 }
548 res := strings.Split(stdout, "\n")
549 if len(res) != 1 || res[0] != testInjectedIP {
550 framework.Logf("Expect command `%v` to return %s, got: %v", cmd, testInjectedIP, res)
551 return false, nil
552 }
553 return true, nil
554 }
555 err = wait.PollImmediate(5*time.Second, 3*time.Minute, digFunc)
556 framework.ExpectNoError(err, "failed to verify customized name server and search path")
557
558
559 })
560
561 ginkgo.It("should work with the pod containing more than 6 DNS search paths and longer than 256 search list characters", func(ctx context.Context) {
562
563 namesToResolve := []string{
564 "kubernetes.default",
565 "kubernetes.default.svc",
566 }
567 hostFQDN := fmt.Sprintf("%s.%s.%s.svc.%s", dnsTestPodHostName, dnsTestServiceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
568 hostEntries := []string{hostFQDN, dnsTestPodHostName}
569
570 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostEntries, "", "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
571 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostEntries, "", "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
572 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
573 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
574
575 ginkgo.By("Creating a pod with expanded DNS configuration to probe DNS")
576 testNdotsValue := "5"
577 testSearchPaths := []string{
578 fmt.Sprintf("%038d.k8s.io", 1),
579 fmt.Sprintf("%038d.k8s.io", 2),
580 fmt.Sprintf("%038d.k8s.io", 3),
581 fmt.Sprintf("%038d.k8s.io", 4),
582 fmt.Sprintf("%038d.k8s.io", 5),
583 fmt.Sprintf("%038d.k8s.io", 6),
584 }
585 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
586 pod.Spec.DNSPolicy = v1.DNSClusterFirst
587 pod.Spec.DNSConfig = &v1.PodDNSConfig{
588 Searches: testSearchPaths,
589 Options: []v1.PodDNSConfigOption{
590 {
591 Name: "ndots",
592 Value: &testNdotsValue,
593 },
594 },
595 }
596 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
597 })
598
599 })
600
601 var _ = common.SIGDescribe("DNS HostNetwork", func() {
602 f := framework.NewDefaultFramework("hostnetworkdns")
603 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
604
605 ginkgo.It("should resolve DNS of partial qualified names for services on hostNetwork pods with dnsPolicy: ClusterFirstWithHostNet [LinuxOnly]", func(ctx context.Context) {
606
607 ginkgo.By("Creating a test headless service")
608 testServiceSelector := map[string]string{
609 "dns-test": "true",
610 }
611 headlessService := e2eservice.CreateServiceSpec(dnsTestServiceName, "", true, testServiceSelector)
612 _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, headlessService, metav1.CreateOptions{})
613 framework.ExpectNoError(err, "failed to create headless service: %s", dnsTestServiceName)
614
615 regularServiceName := "test-service-2"
616 regularService := e2eservice.CreateServiceSpec(regularServiceName, "", false, testServiceSelector)
617 regularService, err = f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, regularService, metav1.CreateOptions{})
618 framework.ExpectNoError(err, "failed to create regular service: %s", regularServiceName)
619
620
621
622 namesToResolve := []string{
623 headlessService.Name,
624 fmt.Sprintf("%s.%s", headlessService.Name, f.Namespace.Name),
625 fmt.Sprintf("%s.%s.svc", headlessService.Name, f.Namespace.Name),
626 fmt.Sprintf("_http._tcp.%s.%s.svc", headlessService.Name, f.Namespace.Name),
627 fmt.Sprintf("_http._tcp.%s.%s.svc", regularService.Name, f.Namespace.Name),
628 }
629
630
631 wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "wheezy", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
632 jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "jessie", f.Namespace.Name, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterIsIPv6())
633 ginkgo.By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
634 ginkgo.By("Running these commands on jessie: " + jessieProbeCmd + "\n")
635
636
637 ginkgo.By("creating a pod to probe DNS")
638 pod := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, dnsTestPodHostName, dnsTestServiceName)
639 pod.ObjectMeta.Labels = testServiceSelector
640 pod.Spec.HostNetwork = true
641 pod.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
642 validateDNSResults(ctx, f, pod, append(wheezyFileNames, jessieFileNames...))
643 })
644
645 })
646
View as plain text