dns_configmap.go 16 KB

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