dns_configmap.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package network
  14. import (
  15. "context"
  16. "fmt"
  17. "time"
  18. v1 "k8s.io/api/core/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. "k8s.io/apimachinery/pkg/util/wait"
  21. "k8s.io/kubernetes/test/e2e/framework"
  22. e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
  23. e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
  24. "github.com/onsi/ginkgo"
  25. )
  26. type dnsFederationsConfigMapTest struct {
  27. dnsTestCommon
  28. fedMap map[string]string
  29. isValid bool
  30. }
  31. var (
  32. googleDNSHostname = "dns.google"
  33. // The ConfigMap update mechanism takes longer than the standard
  34. // wait.ForeverTestTimeout.
  35. moreForeverTestTimeout = 2 * 60 * time.Second
  36. )
  37. var _ = SIGDescribe("DNS configMap federations [Feature:Federation]", func() {
  38. t := &dnsFederationsConfigMapTest{dnsTestCommon: newDNSTestCommon()}
  39. ginkgo.It("should be able to change federation configuration [Slow][Serial]", func() {
  40. t.c = t.f.ClientSet
  41. t.run()
  42. })
  43. })
  44. func (t *dnsFederationsConfigMapTest) run() {
  45. t.init()
  46. defer t.c.CoreV1().ConfigMaps(t.ns).Delete(context.TODO(), t.name, nil)
  47. t.createUtilPodLabel("e2e-dns-configmap")
  48. defer t.deleteUtilPod()
  49. originalConfigMapData := t.fetchDNSConfigMapData()
  50. defer t.restoreDNSConfigMap(originalConfigMapData)
  51. t.validate(framework.TestContext.ClusterDNSDomain)
  52. if t.name == "coredns" {
  53. t.labels = []string{"abc", "ghi"}
  54. valid1 := map[string]string{
  55. "Corefile": fmt.Sprintf(`.:53 {
  56. health
  57. ready
  58. kubernetes %v in-addr.arpa ip6.arpa {
  59. pods insecure
  60. upstream
  61. fallthrough in-addr.arpa ip6.arpa
  62. ttl 30
  63. }
  64. federation %v {
  65. abc def.com
  66. }
  67. forward . /etc/resolv.conf
  68. }`, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterDNSDomain)}
  69. valid1m := map[string]string{t.labels[0]: "def.com"}
  70. valid2 := map[string]string{
  71. "Corefile": fmt.Sprintf(`:53 {
  72. health
  73. ready
  74. kubernetes %v in-addr.arpa ip6.arpa {
  75. pods insecure
  76. upstream
  77. fallthrough in-addr.arpa ip6.arpa
  78. ttl 30
  79. }
  80. federation %v {
  81. ghi xyz.com
  82. }
  83. forward . /etc/resolv.conf
  84. }`, framework.TestContext.ClusterDNSDomain, framework.TestContext.ClusterDNSDomain)}
  85. valid2m := map[string]string{t.labels[1]: "xyz.com"}
  86. ginkgo.By("default -> valid1")
  87. t.setConfigMap(&v1.ConfigMap{Data: valid1}, valid1m, true)
  88. t.deleteCoreDNSPods()
  89. t.validate(framework.TestContext.ClusterDNSDomain)
  90. ginkgo.By("valid1 -> valid2")
  91. t.setConfigMap(&v1.ConfigMap{Data: valid2}, valid2m, true)
  92. t.deleteCoreDNSPods()
  93. t.validate(framework.TestContext.ClusterDNSDomain)
  94. ginkgo.By("valid2 -> default")
  95. t.setConfigMap(&v1.ConfigMap{Data: originalConfigMapData}, nil, false)
  96. t.deleteCoreDNSPods()
  97. t.validate(framework.TestContext.ClusterDNSDomain)
  98. t.restoreDNSConfigMap(originalConfigMapData)
  99. } else {
  100. t.labels = []string{"abc", "ghi"}
  101. valid1 := map[string]string{"federations": t.labels[0] + "=def"}
  102. valid1m := map[string]string{t.labels[0]: "def"}
  103. valid2 := map[string]string{"federations": t.labels[1] + "=xyz"}
  104. valid2m := map[string]string{t.labels[1]: "xyz"}
  105. invalid := map[string]string{"federations": "invalid.map=xyz"}
  106. ginkgo.By("empty -> valid1")
  107. t.setConfigMap(&v1.ConfigMap{Data: valid1}, valid1m, true)
  108. t.validate(framework.TestContext.ClusterDNSDomain)
  109. ginkgo.By("valid1 -> valid2")
  110. t.setConfigMap(&v1.ConfigMap{Data: valid2}, valid2m, true)
  111. t.validate(framework.TestContext.ClusterDNSDomain)
  112. ginkgo.By("valid2 -> invalid")
  113. t.setConfigMap(&v1.ConfigMap{Data: invalid}, nil, false)
  114. t.validate(framework.TestContext.ClusterDNSDomain)
  115. ginkgo.By("invalid -> valid1")
  116. t.setConfigMap(&v1.ConfigMap{Data: valid1}, valid1m, true)
  117. t.validate(framework.TestContext.ClusterDNSDomain)
  118. ginkgo.By("valid1 -> deleted")
  119. t.deleteConfigMap()
  120. t.validate(framework.TestContext.ClusterDNSDomain)
  121. ginkgo.By("deleted -> invalid")
  122. t.setConfigMap(&v1.ConfigMap{Data: invalid}, nil, false)
  123. t.validate(framework.TestContext.ClusterDNSDomain)
  124. }
  125. }
  126. func (t *dnsFederationsConfigMapTest) validate(dnsDomain string) {
  127. federations := t.fedMap
  128. if len(federations) == 0 {
  129. ginkgo.By(fmt.Sprintf("Validating federation labels %v do not exist", t.labels))
  130. for _, label := range t.labels {
  131. var federationDNS = fmt.Sprintf("e2e-dns-configmap.%s.%s.svc.%s.",
  132. t.f.Namespace.Name, label, framework.TestContext.ClusterDNSDomain)
  133. predicate := func(actual []string) bool {
  134. return len(actual) == 0
  135. }
  136. t.checkDNSRecordFrom(federationDNS, predicate, "cluster-dns", wait.ForeverTestTimeout)
  137. }
  138. } else {
  139. for label := range federations {
  140. var federationDNS = fmt.Sprintf("%s.%s.%s.svc.%s.",
  141. t.utilService.ObjectMeta.Name, t.f.Namespace.Name, label, framework.TestContext.ClusterDNSDomain)
  142. var localDNS = fmt.Sprintf("%s.%s.svc.%s.",
  143. t.utilService.ObjectMeta.Name, t.f.Namespace.Name, framework.TestContext.ClusterDNSDomain)
  144. if t.name == "coredns" {
  145. localDNS = t.utilService.Spec.ClusterIP
  146. }
  147. // Check local mapping. Checking a remote mapping requires
  148. // creating an arbitrary DNS record which is not possible at the
  149. // moment.
  150. ginkgo.By(fmt.Sprintf("Validating federation record %v", label))
  151. predicate := func(actual []string) bool {
  152. for _, v := range actual {
  153. if v == localDNS {
  154. return true
  155. }
  156. }
  157. return false
  158. }
  159. t.checkDNSRecordFrom(federationDNS, predicate, "cluster-dns", wait.ForeverTestTimeout)
  160. }
  161. }
  162. }
  163. func (t *dnsFederationsConfigMapTest) setConfigMap(cm *v1.ConfigMap, fedMap map[string]string, isValid bool) {
  164. t.fedMap = nil
  165. if isValid {
  166. t.fedMap = fedMap
  167. }
  168. t.isValid = isValid
  169. t.dnsTestCommon.setConfigMap(cm)
  170. }
  171. func (t *dnsFederationsConfigMapTest) deleteConfigMap() {
  172. t.isValid = false
  173. t.dnsTestCommon.deleteConfigMap()
  174. }
  175. type dnsNameserverTest struct {
  176. dnsTestCommon
  177. }
  178. func (t *dnsNameserverTest) run(isIPv6 bool) {
  179. t.init()
  180. t.createUtilPodLabel("e2e-dns-configmap")
  181. defer t.deleteUtilPod()
  182. originalConfigMapData := t.fetchDNSConfigMapData()
  183. defer t.restoreDNSConfigMap(originalConfigMapData)
  184. if isIPv6 {
  185. t.createDNSServer(map[string]string{
  186. "abc.acme.local": "2606:4700:4700::1111",
  187. "def.acme.local": "2606:4700:4700::2222",
  188. "widget.local": "2606:4700:4700::3333",
  189. })
  190. } else {
  191. t.createDNSServer(map[string]string{
  192. "abc.acme.local": "1.1.1.1",
  193. "def.acme.local": "2.2.2.2",
  194. "widget.local": "3.3.3.3",
  195. })
  196. }
  197. defer t.deleteDNSServerPod()
  198. if t.name == "coredns" {
  199. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  200. "Corefile": fmt.Sprintf(`.:53 {
  201. health
  202. ready
  203. kubernetes %v in-addr.arpa ip6.arpa {
  204. pods insecure
  205. upstream
  206. fallthrough in-addr.arpa ip6.arpa
  207. ttl 30
  208. }
  209. forward . %v
  210. }
  211. acme.local:53 {
  212. forward . %v
  213. }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP, t.dnsServerPod.Status.PodIP),
  214. }})
  215. t.deleteCoreDNSPods()
  216. } else {
  217. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  218. "stubDomains": fmt.Sprintf(`{"acme.local":["%v"]}`, t.dnsServerPod.Status.PodIP),
  219. "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
  220. }})
  221. }
  222. if isIPv6 {
  223. t.checkDNSRecordFrom(
  224. "abc.acme.local",
  225. func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::1111" },
  226. "cluster-dns-ipv6",
  227. moreForeverTestTimeout)
  228. t.checkDNSRecordFrom(
  229. "def.acme.local",
  230. func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::2222" },
  231. "cluster-dns-ipv6",
  232. moreForeverTestTimeout)
  233. t.checkDNSRecordFrom(
  234. "widget.local",
  235. func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::3333" },
  236. "cluster-dns-ipv6",
  237. moreForeverTestTimeout)
  238. } else {
  239. t.checkDNSRecordFrom(
  240. "abc.acme.local",
  241. func(actual []string) bool { return len(actual) == 1 && actual[0] == "1.1.1.1" },
  242. "cluster-dns",
  243. moreForeverTestTimeout)
  244. t.checkDNSRecordFrom(
  245. "def.acme.local",
  246. func(actual []string) bool { return len(actual) == 1 && actual[0] == "2.2.2.2" },
  247. "cluster-dns",
  248. moreForeverTestTimeout)
  249. t.checkDNSRecordFrom(
  250. "widget.local",
  251. func(actual []string) bool { return len(actual) == 1 && actual[0] == "3.3.3.3" },
  252. "cluster-dns",
  253. moreForeverTestTimeout)
  254. }
  255. t.restoreDNSConfigMap(originalConfigMapData)
  256. // Wait for the deleted ConfigMap to take effect, otherwise the
  257. // configuration can bleed into other tests.
  258. t.checkDNSRecordFrom(
  259. "abc.acme.local",
  260. func(actual []string) bool { return len(actual) == 0 },
  261. "cluster-dns",
  262. moreForeverTestTimeout)
  263. }
  264. type dnsPtrFwdTest struct {
  265. dnsTestCommon
  266. }
  267. func (t *dnsPtrFwdTest) run(isIPv6 bool) {
  268. t.init()
  269. t.createUtilPodLabel("e2e-dns-configmap")
  270. defer t.deleteUtilPod()
  271. originalConfigMapData := t.fetchDNSConfigMapData()
  272. defer t.restoreDNSConfigMap(originalConfigMapData)
  273. t.createDNSServerWithPtrRecord(isIPv6)
  274. defer t.deleteDNSServerPod()
  275. // Should still be able to lookup public nameserver without explicit upstream nameserver set.
  276. if isIPv6 {
  277. t.checkDNSRecordFrom(
  278. "2001:4860:4860::8888",
  279. func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." },
  280. "ptr-record",
  281. moreForeverTestTimeout)
  282. } else {
  283. t.checkDNSRecordFrom(
  284. "8.8.8.8",
  285. func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." },
  286. "ptr-record",
  287. moreForeverTestTimeout)
  288. }
  289. if t.name == "coredns" {
  290. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  291. "Corefile": fmt.Sprintf(`.:53 {
  292. health
  293. ready
  294. kubernetes %v in-addr.arpa ip6.arpa {
  295. pods insecure
  296. upstream
  297. fallthrough in-addr.arpa ip6.arpa
  298. ttl 30
  299. }
  300. forward . %v
  301. }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP),
  302. }})
  303. t.deleteCoreDNSPods()
  304. } else {
  305. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  306. "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
  307. }})
  308. }
  309. if isIPv6 {
  310. t.checkDNSRecordFrom(
  311. "2001:db8::29",
  312. func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." },
  313. "ptr-record",
  314. moreForeverTestTimeout)
  315. t.restoreDNSConfigMap(originalConfigMapData)
  316. t.checkDNSRecordFrom(
  317. "2001:db8::29",
  318. func(actual []string) bool { return len(actual) == 0 },
  319. "ptr-record",
  320. moreForeverTestTimeout)
  321. } else {
  322. t.checkDNSRecordFrom(
  323. "192.0.2.123",
  324. func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." },
  325. "ptr-record",
  326. moreForeverTestTimeout)
  327. t.restoreDNSConfigMap(originalConfigMapData)
  328. t.checkDNSRecordFrom(
  329. "192.0.2.123",
  330. func(actual []string) bool { return len(actual) == 0 },
  331. "ptr-record",
  332. moreForeverTestTimeout)
  333. }
  334. }
  335. type dnsExternalNameTest struct {
  336. dnsTestCommon
  337. }
  338. func (t *dnsExternalNameTest) run(isIPv6 bool) {
  339. t.init()
  340. t.createUtilPodLabel("e2e-dns-configmap")
  341. defer t.deleteUtilPod()
  342. originalConfigMapData := t.fetchDNSConfigMapData()
  343. defer t.restoreDNSConfigMap(originalConfigMapData)
  344. fooHostname := "foo.example.com"
  345. if isIPv6 {
  346. t.createDNSServer(map[string]string{
  347. fooHostname: "2001:db8::29",
  348. })
  349. } else {
  350. t.createDNSServer(map[string]string{
  351. fooHostname: "192.0.2.123",
  352. })
  353. }
  354. defer t.deleteDNSServerPod()
  355. f := t.f
  356. serviceName := "dns-externalname-upstream-test"
  357. externalNameService := e2eservice.CreateServiceSpec(serviceName, googleDNSHostname, false, nil)
  358. if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(context.TODO(), externalNameService, metav1.CreateOptions{}); err != nil {
  359. ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err))
  360. }
  361. serviceNameLocal := "dns-externalname-upstream-local"
  362. externalNameServiceLocal := e2eservice.CreateServiceSpec(serviceNameLocal, fooHostname, false, nil)
  363. if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(context.TODO(), externalNameServiceLocal, metav1.CreateOptions{}); err != nil {
  364. ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err))
  365. }
  366. defer func() {
  367. ginkgo.By("deleting the test externalName service")
  368. defer ginkgo.GinkgoRecover()
  369. f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(context.TODO(), externalNameService.Name, nil)
  370. f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete(context.TODO(), externalNameServiceLocal.Name, nil)
  371. }()
  372. if isIPv6 {
  373. t.checkDNSRecordFrom(
  374. fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
  375. func(actual []string) bool {
  376. return len(actual) >= 1 && actual[0] == googleDNSHostname+"."
  377. },
  378. "cluster-dns-ipv6",
  379. moreForeverTestTimeout)
  380. } else {
  381. t.checkDNSRecordFrom(
  382. fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
  383. func(actual []string) bool {
  384. return len(actual) >= 1 && actual[0] == googleDNSHostname+"."
  385. },
  386. "cluster-dns",
  387. moreForeverTestTimeout)
  388. }
  389. if t.name == "coredns" {
  390. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  391. "Corefile": fmt.Sprintf(`.:53 {
  392. health
  393. ready
  394. kubernetes %v in-addr.arpa ip6.arpa {
  395. pods insecure
  396. upstream
  397. fallthrough in-addr.arpa ip6.arpa
  398. ttl 30
  399. }
  400. forward . %v
  401. }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP),
  402. }})
  403. t.deleteCoreDNSPods()
  404. } else {
  405. t.setConfigMap(&v1.ConfigMap{Data: map[string]string{
  406. "upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
  407. }})
  408. }
  409. if isIPv6 {
  410. t.checkDNSRecordFrom(
  411. fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
  412. func(actual []string) bool {
  413. return len(actual) >= 1 && actual[0] == fooHostname+"." && actual[1] == "2001:db8::29"
  414. },
  415. "cluster-dns-ipv6",
  416. moreForeverTestTimeout)
  417. } else {
  418. t.checkDNSRecordFrom(
  419. fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
  420. func(actual []string) bool {
  421. return len(actual) == 2 && actual[0] == fooHostname+"." && actual[1] == "192.0.2.123"
  422. },
  423. "cluster-dns",
  424. moreForeverTestTimeout)
  425. }
  426. t.restoreDNSConfigMap(originalConfigMapData)
  427. }
  428. var _ = SIGDescribe("DNS configMap nameserver [IPv4]", func() {
  429. ginkgo.Context("Change stubDomain", func() {
  430. nsTest := &dnsNameserverTest{dnsTestCommon: newDNSTestCommon()}
  431. ginkgo.It("should be able to change stubDomain configuration [Slow][Serial]", func() {
  432. nsTest.c = nsTest.f.ClientSet
  433. nsTest.run(false)
  434. })
  435. })
  436. ginkgo.Context("Forward PTR lookup", func() {
  437. fwdTest := &dnsPtrFwdTest{dnsTestCommon: newDNSTestCommon()}
  438. ginkgo.It("should forward PTR records lookup to upstream nameserver [Slow][Serial]", func() {
  439. fwdTest.c = fwdTest.f.ClientSet
  440. fwdTest.run(false)
  441. })
  442. })
  443. ginkgo.Context("Forward external name lookup", func() {
  444. externalNameTest := &dnsExternalNameTest{dnsTestCommon: newDNSTestCommon()}
  445. ginkgo.It("should forward externalname lookup to upstream nameserver [Slow][Serial]", func() {
  446. externalNameTest.c = externalNameTest.f.ClientSet
  447. externalNameTest.run(false)
  448. })
  449. })
  450. })
  451. var _ = SIGDescribe("DNS configMap nameserver [Feature:Networking-IPv6] [LinuxOnly]", func() {
  452. ginkgo.BeforeEach(func() {
  453. // IPv6 is not supported on Windows.
  454. e2eskipper.SkipIfNodeOSDistroIs("windows")
  455. })
  456. ginkgo.Context("Change stubDomain", func() {
  457. nsTest := &dnsNameserverTest{dnsTestCommon: newDNSTestCommon()}
  458. ginkgo.It("should be able to change stubDomain configuration [Slow][Serial]", func() {
  459. nsTest.c = nsTest.f.ClientSet
  460. nsTest.run(true)
  461. })
  462. })
  463. ginkgo.Context("Forward PTR lookup", func() {
  464. fwdTest := &dnsPtrFwdTest{dnsTestCommon: newDNSTestCommon()}
  465. ginkgo.It("should forward PTR records lookup to upstream nameserver [Slow][Serial]", func() {
  466. fwdTest.c = fwdTest.f.ClientSet
  467. fwdTest.run(true)
  468. })
  469. })
  470. ginkgo.Context("Forward external name lookup", func() {
  471. externalNameTest := &dnsExternalNameTest{dnsTestCommon: newDNSTestCommon()}
  472. ginkgo.It("should forward externalname lookup to upstream nameserver [Slow][Serial]", func() {
  473. externalNameTest.c = externalNameTest.f.ClientSet
  474. externalNameTest.run(true)
  475. })
  476. })
  477. })