k8s.io/kubernetes@v1.29.3/test/e2e/network/dns_configmap.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package network 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/kubernetes/test/e2e/framework" 27 e2eservice "k8s.io/kubernetes/test/e2e/framework/service" 28 "k8s.io/kubernetes/test/e2e/network/common" 29 30 "github.com/onsi/ginkgo/v2" 31 ) 32 33 var ( 34 googleDNSHostname = "dns.google" 35 // The ConfigMap update mechanism takes longer than the standard 36 // wait.ForeverTestTimeout. 37 moreForeverTestTimeout = 2 * 60 * time.Second 38 ) 39 40 type dnsNameserverTest struct { 41 dnsTestCommon 42 } 43 44 func (t *dnsNameserverTest) run(ctx context.Context, isIPv6 bool) { 45 t.init(ctx) 46 47 t.createUtilPodLabel(ctx, "e2e-dns-configmap") 48 ginkgo.DeferCleanup(t.deleteUtilPod) 49 originalConfigMapData := t.fetchDNSConfigMapData(ctx) 50 ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData) 51 52 if isIPv6 { 53 t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{ 54 "abc.acme.local": "2606:4700:4700::1111", 55 "def.acme.local": "2606:4700:4700::2222", 56 "widget.local": "2606:4700:4700::3333", 57 }) 58 } else { 59 t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{ 60 "abc.acme.local": "1.1.1.1", 61 "def.acme.local": "2.2.2.2", 62 "widget.local": "3.3.3.3", 63 }) 64 } 65 ginkgo.DeferCleanup(t.deleteDNSServerPod) 66 67 if t.name == "coredns" { 68 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 69 "Corefile": fmt.Sprintf(`.:53 { 70 health 71 ready 72 kubernetes %v in-addr.arpa ip6.arpa { 73 pods insecure 74 fallthrough in-addr.arpa ip6.arpa 75 ttl 30 76 } 77 forward . %v 78 } 79 acme.local:53 { 80 forward . %v 81 }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP, t.dnsServerPod.Status.PodIP), 82 }}) 83 84 t.deleteCoreDNSPods(ctx) 85 } else { 86 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 87 "stubDomains": fmt.Sprintf(`{"acme.local":["%v"]}`, t.dnsServerPod.Status.PodIP), 88 "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP), 89 }}) 90 } 91 92 if isIPv6 { 93 t.checkDNSRecordFrom( 94 "abc.acme.local", 95 func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::1111" }, 96 "cluster-dns-ipv6", 97 moreForeverTestTimeout) 98 t.checkDNSRecordFrom( 99 "def.acme.local", 100 func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::2222" }, 101 "cluster-dns-ipv6", 102 moreForeverTestTimeout) 103 t.checkDNSRecordFrom( 104 "widget.local", 105 func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::3333" }, 106 "cluster-dns-ipv6", 107 moreForeverTestTimeout) 108 } else { 109 t.checkDNSRecordFrom( 110 "abc.acme.local", 111 func(actual []string) bool { return len(actual) == 1 && actual[0] == "1.1.1.1" }, 112 "cluster-dns", 113 moreForeverTestTimeout) 114 t.checkDNSRecordFrom( 115 "def.acme.local", 116 func(actual []string) bool { return len(actual) == 1 && actual[0] == "2.2.2.2" }, 117 "cluster-dns", 118 moreForeverTestTimeout) 119 t.checkDNSRecordFrom( 120 "widget.local", 121 func(actual []string) bool { return len(actual) == 1 && actual[0] == "3.3.3.3" }, 122 "cluster-dns", 123 moreForeverTestTimeout) 124 } 125 126 t.restoreDNSConfigMap(ctx, originalConfigMapData) 127 // Wait for the deleted ConfigMap to take effect, otherwise the 128 // configuration can bleed into other tests. 129 t.checkDNSRecordFrom( 130 "abc.acme.local", 131 func(actual []string) bool { return len(actual) == 0 }, 132 "cluster-dns", 133 moreForeverTestTimeout) 134 } 135 136 type dnsPtrFwdTest struct { 137 dnsTestCommon 138 } 139 140 func (t *dnsPtrFwdTest) run(ctx context.Context, isIPv6 bool) { 141 t.init(ctx) 142 143 t.createUtilPodLabel(ctx, "e2e-dns-configmap") 144 ginkgo.DeferCleanup(t.deleteUtilPod) 145 originalConfigMapData := t.fetchDNSConfigMapData(ctx) 146 ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData) 147 148 t.createDNSServerWithPtrRecord(ctx, t.f.Namespace.Name, isIPv6) 149 ginkgo.DeferCleanup(t.deleteDNSServerPod) 150 151 // Should still be able to lookup public nameserver without explicit upstream nameserver set. 152 if isIPv6 { 153 t.checkDNSRecordFrom( 154 "2001:4860:4860::8888", 155 func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." }, 156 "ptr-record", 157 moreForeverTestTimeout) 158 } else { 159 t.checkDNSRecordFrom( 160 "8.8.8.8", 161 func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." }, 162 "ptr-record", 163 moreForeverTestTimeout) 164 } 165 166 if t.name == "coredns" { 167 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 168 "Corefile": fmt.Sprintf(`.:53 { 169 health 170 ready 171 kubernetes %v in-addr.arpa ip6.arpa { 172 pods insecure 173 fallthrough in-addr.arpa ip6.arpa 174 ttl 30 175 } 176 forward . %v 177 }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP), 178 }}) 179 180 t.deleteCoreDNSPods(ctx) 181 } else { 182 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 183 "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP), 184 }}) 185 } 186 187 if isIPv6 { 188 t.checkDNSRecordFrom( 189 "2001:db8::29", 190 func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." }, 191 "ptr-record", 192 moreForeverTestTimeout) 193 194 t.restoreDNSConfigMap(ctx, originalConfigMapData) 195 t.checkDNSRecordFrom( 196 "2001:db8::29", 197 func(actual []string) bool { return len(actual) == 0 }, 198 "ptr-record", 199 moreForeverTestTimeout) 200 201 } else { 202 t.checkDNSRecordFrom( 203 "192.0.2.123", 204 func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." }, 205 "ptr-record", 206 moreForeverTestTimeout) 207 208 t.restoreDNSConfigMap(ctx, originalConfigMapData) 209 t.checkDNSRecordFrom( 210 "192.0.2.123", 211 func(actual []string) bool { return len(actual) == 0 }, 212 "ptr-record", 213 moreForeverTestTimeout) 214 } 215 } 216 217 type dnsExternalNameTest struct { 218 dnsTestCommon 219 } 220 221 func (t *dnsExternalNameTest) run(ctx context.Context, isIPv6 bool) { 222 t.init(ctx) 223 224 t.createUtilPodLabel(ctx, "e2e-dns-configmap") 225 ginkgo.DeferCleanup(t.deleteUtilPod) 226 originalConfigMapData := t.fetchDNSConfigMapData(ctx) 227 ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData) 228 229 fooHostname := "foo.example.com" 230 if isIPv6 { 231 t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{ 232 fooHostname: "2001:db8::29", 233 }) 234 } else { 235 t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{ 236 fooHostname: "192.0.2.123", 237 }) 238 } 239 ginkgo.DeferCleanup(t.deleteDNSServerPod) 240 241 f := t.f 242 serviceName := "dns-externalname-upstream-test" 243 externalNameService := e2eservice.CreateServiceSpec(serviceName, googleDNSHostname, false, nil) 244 if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, externalNameService, metav1.CreateOptions{}); err != nil { 245 ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err)) 246 } 247 ginkgo.DeferCleanup(f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete, externalNameService.Name, metav1.DeleteOptions{}) 248 serviceNameLocal := "dns-externalname-upstream-local" 249 externalNameServiceLocal := e2eservice.CreateServiceSpec(serviceNameLocal, fooHostname, false, nil) 250 if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, externalNameServiceLocal, metav1.CreateOptions{}); err != nil { 251 ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err)) 252 } 253 ginkgo.DeferCleanup(f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete, externalNameServiceLocal.Name, metav1.DeleteOptions{}) 254 255 if isIPv6 { 256 t.checkDNSRecordFrom( 257 fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain), 258 func(actual []string) bool { 259 return len(actual) >= 1 && actual[0] == googleDNSHostname+"." 260 }, 261 "cluster-dns-ipv6", 262 moreForeverTestTimeout) 263 } else { 264 t.checkDNSRecordFrom( 265 fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain), 266 func(actual []string) bool { 267 return len(actual) >= 1 && actual[0] == googleDNSHostname+"." 268 }, 269 "cluster-dns", 270 moreForeverTestTimeout) 271 } 272 273 if t.name == "coredns" { 274 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 275 "Corefile": fmt.Sprintf(`.:53 { 276 health 277 ready 278 kubernetes %v in-addr.arpa ip6.arpa { 279 pods insecure 280 fallthrough in-addr.arpa ip6.arpa 281 ttl 30 282 } 283 forward . %v 284 }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP), 285 }}) 286 287 t.deleteCoreDNSPods(ctx) 288 } else { 289 t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{ 290 "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP), 291 }}) 292 } 293 if isIPv6 { 294 t.checkDNSRecordFrom( 295 fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain), 296 func(actual []string) bool { 297 return len(actual) >= 2 && actual[0] == fooHostname+"." && actual[1] == "2001:db8::29" 298 }, 299 "cluster-dns-ipv6", 300 moreForeverTestTimeout) 301 } else { 302 t.checkDNSRecordFrom( 303 fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain), 304 func(actual []string) bool { 305 return len(actual) == 2 && actual[0] == fooHostname+"." && actual[1] == "192.0.2.123" 306 }, 307 "cluster-dns", 308 moreForeverTestTimeout) 309 } 310 311 t.restoreDNSConfigMap(ctx, originalConfigMapData) 312 } 313 314 var _ = common.SIGDescribe("DNS configMap nameserver", func() { 315 316 ginkgo.Context("Change stubDomain", func() { 317 nsTest := &dnsNameserverTest{dnsTestCommon: newDNSTestCommon()} 318 319 framework.It("should be able to change stubDomain configuration", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) { 320 nsTest.c = nsTest.f.ClientSet 321 nsTest.run(ctx, framework.TestContext.ClusterIsIPv6()) 322 }) 323 }) 324 325 ginkgo.Context("Forward PTR lookup", func() { 326 fwdTest := &dnsPtrFwdTest{dnsTestCommon: newDNSTestCommon()} 327 328 framework.It("should forward PTR records lookup to upstream nameserver", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) { 329 fwdTest.c = fwdTest.f.ClientSet 330 fwdTest.run(ctx, framework.TestContext.ClusterIsIPv6()) 331 }) 332 }) 333 334 ginkgo.Context("Forward external name lookup", func() { 335 externalNameTest := &dnsExternalNameTest{dnsTestCommon: newDNSTestCommon()} 336 337 framework.It("should forward externalname lookup to upstream nameserver", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) { 338 externalNameTest.c = externalNameTest.f.ClientSet 339 externalNameTest.run(ctx, framework.TestContext.ClusterIsIPv6()) 340 }) 341 }) 342 })