dns_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /*
  2. Copyright 2017 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 dns
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. "net"
  18. "os"
  19. "strings"
  20. "testing"
  21. "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/types"
  24. "k8s.io/apimachinery/pkg/util/sets"
  25. "k8s.io/client-go/tools/record"
  26. runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
  27. "github.com/stretchr/testify/assert"
  28. "github.com/stretchr/testify/require"
  29. )
  30. var (
  31. fetchEvent = func(recorder *record.FakeRecorder) string {
  32. select {
  33. case event := <-recorder.Events:
  34. return event
  35. default:
  36. return ""
  37. }
  38. }
  39. )
  40. func TestParseResolvConf(t *testing.T) {
  41. testCases := []struct {
  42. data string
  43. nameservers []string
  44. searches []string
  45. options []string
  46. isErr bool
  47. }{
  48. {"", []string{}, []string{}, []string{}, false},
  49. {" ", []string{}, []string{}, []string{}, false},
  50. {"\n", []string{}, []string{}, []string{}, false},
  51. {"\t\n\t", []string{}, []string{}, []string{}, false},
  52. {"#comment\n", []string{}, []string{}, []string{}, false},
  53. {" #comment\n", []string{}, []string{}, []string{}, false},
  54. {"#comment\n#comment", []string{}, []string{}, []string{}, false},
  55. {"#comment\nnameserver", []string{}, []string{}, []string{}, true}, // nameserver empty
  56. {"#comment\nnameserver\nsearch", []string{}, []string{}, []string{}, true}, // nameserver and search empty
  57. {"#comment\nnameserver 1.2.3.4\nsearch", []string{"1.2.3.4"}, []string{}, []string{}, false}, // nameserver specified and search empty
  58. {"nameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}, []string{}, false},
  59. {" nameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}, []string{}, false},
  60. {"\tnameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}, []string{}, false},
  61. {"nameserver\t1.2.3.4", []string{"1.2.3.4"}, []string{}, []string{}, false},
  62. {"nameserver \t 1.2.3.4", []string{"1.2.3.4"}, []string{}, []string{}, false},
  63. {"nameserver 1.2.3.4\nnameserver 5.6.7.8", []string{"1.2.3.4", "5.6.7.8"}, []string{}, []string{}, false},
  64. {"nameserver 1.2.3.4 #comment", []string{"1.2.3.4"}, []string{}, []string{}, false},
  65. {"search ", []string{}, []string{}, []string{}, false}, // search empty
  66. {"search foo", []string{}, []string{"foo"}, []string{}, false},
  67. {"search foo bar", []string{}, []string{"foo", "bar"}, []string{}, false},
  68. {"search foo. bar", []string{}, []string{"foo", "bar"}, []string{}, false},
  69. {"search foo bar bat\n", []string{}, []string{"foo", "bar", "bat"}, []string{}, false},
  70. {"search foo\nsearch bar", []string{}, []string{"bar"}, []string{}, false},
  71. {"nameserver 1.2.3.4\nsearch foo bar", []string{"1.2.3.4"}, []string{"foo", "bar"}, []string{}, false},
  72. {"nameserver 1.2.3.4\nsearch foo\nnameserver 5.6.7.8\nsearch bar", []string{"1.2.3.4", "5.6.7.8"}, []string{"bar"}, []string{}, false},
  73. {"#comment\nnameserver 1.2.3.4\n#comment\nsearch foo\ncomment", []string{"1.2.3.4"}, []string{"foo"}, []string{}, false},
  74. {"options ", []string{}, []string{}, []string{}, false},
  75. {"options ndots:5 attempts:2", []string{}, []string{}, []string{"ndots:5", "attempts:2"}, false},
  76. {"options ndots:1\noptions ndots:5 attempts:3", []string{}, []string{}, []string{"ndots:5", "attempts:3"}, false},
  77. {"nameserver 1.2.3.4\nsearch foo\nnameserver 5.6.7.8\nsearch bar\noptions ndots:5 attempts:4", []string{"1.2.3.4", "5.6.7.8"}, []string{"bar"}, []string{"ndots:5", "attempts:4"}, false},
  78. }
  79. for i, tc := range testCases {
  80. ns, srch, opts, err := parseResolvConf(strings.NewReader(tc.data))
  81. if !tc.isErr {
  82. require.NoError(t, err)
  83. assert.EqualValues(t, tc.nameservers, ns, "test case [%d]: name servers", i)
  84. assert.EqualValues(t, tc.searches, srch, "test case [%d] searches", i)
  85. assert.EqualValues(t, tc.options, opts, "test case [%d] options", i)
  86. } else {
  87. require.Error(t, err, "tc.searches %v", tc.searches)
  88. }
  89. }
  90. }
  91. func TestFormDNSSearchFitsLimits(t *testing.T) {
  92. recorder := record.NewFakeRecorder(20)
  93. nodeRef := &v1.ObjectReference{
  94. Kind: "Node",
  95. Name: string("testNode"),
  96. UID: types.UID("testNode"),
  97. Namespace: "",
  98. }
  99. testClusterDNSDomain := "TEST"
  100. configurer := NewConfigurer(recorder, nodeRef, nil, nil, testClusterDNSDomain, "")
  101. pod := &v1.Pod{
  102. ObjectMeta: metav1.ObjectMeta{
  103. UID: "",
  104. Name: "test_pod",
  105. Namespace: "testNS",
  106. Annotations: map[string]string{},
  107. },
  108. }
  109. testCases := []struct {
  110. hostNames []string
  111. resultSearch []string
  112. events []string
  113. }{
  114. {
  115. []string{"testNS.svc.TEST", "svc.TEST", "TEST"},
  116. []string{"testNS.svc.TEST", "svc.TEST", "TEST"},
  117. []string{},
  118. },
  119. {
  120. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"},
  121. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"},
  122. []string{},
  123. },
  124. {
  125. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", strings.Repeat("B", 256), "BBB"},
  126. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA"},
  127. []string{"Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST AAA"},
  128. },
  129. {
  130. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC", "DDD"},
  131. []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC"},
  132. []string{"Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST AAA BBB CCC"},
  133. },
  134. }
  135. for i, tc := range testCases {
  136. dnsSearch := configurer.formDNSSearchFitsLimits(tc.hostNames, pod)
  137. assert.EqualValues(t, tc.resultSearch, dnsSearch, "test [%d]", i)
  138. for _, expectedEvent := range tc.events {
  139. expected := fmt.Sprintf("%s %s %s", v1.EventTypeWarning, "DNSConfigForming", expectedEvent)
  140. event := fetchEvent(recorder)
  141. assert.Equal(t, expected, event, "test [%d]", i)
  142. }
  143. }
  144. }
  145. func TestFormDNSNameserversFitsLimits(t *testing.T) {
  146. recorder := record.NewFakeRecorder(20)
  147. nodeRef := &v1.ObjectReference{
  148. Kind: "Node",
  149. Name: string("testNode"),
  150. UID: types.UID("testNode"),
  151. Namespace: "",
  152. }
  153. testClusterDNSDomain := "TEST"
  154. configurer := NewConfigurer(recorder, nodeRef, nil, nil, testClusterDNSDomain, "")
  155. pod := &v1.Pod{
  156. ObjectMeta: metav1.ObjectMeta{
  157. UID: "",
  158. Name: "test_pod",
  159. Namespace: "testNS",
  160. Annotations: map[string]string{},
  161. },
  162. }
  163. testCases := []struct {
  164. desc string
  165. nameservers []string
  166. expectedNameserver []string
  167. expectedEvent bool
  168. }{
  169. {
  170. desc: "valid: 1 nameserver",
  171. nameservers: []string{"127.0.0.1"},
  172. expectedNameserver: []string{"127.0.0.1"},
  173. expectedEvent: false,
  174. },
  175. {
  176. desc: "valid: 3 nameservers",
  177. nameservers: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8"},
  178. expectedNameserver: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8"},
  179. expectedEvent: false,
  180. },
  181. {
  182. desc: "invalid: 4 nameservers, trimmed to 3",
  183. nameservers: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8", "1.2.3.4"},
  184. expectedNameserver: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8"},
  185. expectedEvent: true,
  186. },
  187. }
  188. for _, tc := range testCases {
  189. appliedNameservers := configurer.formDNSNameserversFitsLimits(tc.nameservers, pod)
  190. assert.EqualValues(t, tc.expectedNameserver, appliedNameservers, tc.desc)
  191. event := fetchEvent(recorder)
  192. if tc.expectedEvent && len(event) == 0 {
  193. t.Errorf("%s: formDNSNameserversFitsLimits(%v) expected event, got no event.", tc.desc, tc.nameservers)
  194. } else if !tc.expectedEvent && len(event) > 0 {
  195. t.Errorf("%s: formDNSNameserversFitsLimits(%v) expected no event, got event: %v", tc.desc, tc.nameservers, event)
  196. }
  197. }
  198. }
  199. func TestMergeDNSOptions(t *testing.T) {
  200. testOptionValue := "3"
  201. testCases := []struct {
  202. desc string
  203. existingDNSConfigOptions []string
  204. dnsConfigOptions []v1.PodDNSConfigOption
  205. expectedOptions []string
  206. }{
  207. {
  208. desc: "Empty dnsConfigOptions",
  209. existingDNSConfigOptions: []string{"ndots:5", "debug"},
  210. dnsConfigOptions: nil,
  211. expectedOptions: []string{"ndots:5", "debug"},
  212. },
  213. {
  214. desc: "No duplicated entries",
  215. existingDNSConfigOptions: []string{"ndots:5", "debug"},
  216. dnsConfigOptions: []v1.PodDNSConfigOption{
  217. {Name: "single-request"},
  218. {Name: "attempts", Value: &testOptionValue},
  219. },
  220. expectedOptions: []string{"ndots:5", "debug", "single-request", "attempts:3"},
  221. },
  222. {
  223. desc: "Overwrite duplicated entries",
  224. existingDNSConfigOptions: []string{"ndots:5", "debug"},
  225. dnsConfigOptions: []v1.PodDNSConfigOption{
  226. {Name: "ndots", Value: &testOptionValue},
  227. {Name: "debug"},
  228. {Name: "single-request"},
  229. {Name: "attempts", Value: &testOptionValue},
  230. },
  231. expectedOptions: []string{"ndots:3", "debug", "single-request", "attempts:3"},
  232. },
  233. }
  234. for _, tc := range testCases {
  235. options := mergeDNSOptions(tc.existingDNSConfigOptions, tc.dnsConfigOptions)
  236. // Options order may be changed after conversion.
  237. if !sets.NewString(options...).Equal(sets.NewString(tc.expectedOptions...)) {
  238. t.Errorf("%s: mergeDNSOptions(%v, %v)=%v, want %v", tc.desc, tc.existingDNSConfigOptions, tc.dnsConfigOptions, options, tc.expectedOptions)
  239. }
  240. }
  241. }
  242. func TestGetPodDNSType(t *testing.T) {
  243. recorder := record.NewFakeRecorder(20)
  244. nodeRef := &v1.ObjectReference{
  245. Kind: "Node",
  246. Name: string("testNode"),
  247. UID: types.UID("testNode"),
  248. Namespace: "",
  249. }
  250. testClusterDNSDomain := "TEST"
  251. clusterNS := "203.0.113.1"
  252. testClusterDNS := []net.IP{net.ParseIP(clusterNS)}
  253. configurer := NewConfigurer(recorder, nodeRef, nil, nil, testClusterDNSDomain, "")
  254. pod := &v1.Pod{
  255. ObjectMeta: metav1.ObjectMeta{
  256. UID: "",
  257. Name: "test_pod",
  258. Namespace: "testNS",
  259. Annotations: map[string]string{},
  260. },
  261. }
  262. testCases := []struct {
  263. desc string
  264. hasClusterDNS bool
  265. hostNetwork bool
  266. dnsPolicy v1.DNSPolicy
  267. expectedDNSType podDNSType
  268. expectedError bool
  269. }{
  270. {
  271. desc: "valid DNSClusterFirst without hostnetwork",
  272. hasClusterDNS: true,
  273. dnsPolicy: v1.DNSClusterFirst,
  274. expectedDNSType: podDNSCluster,
  275. },
  276. {
  277. desc: "valid DNSClusterFirstWithHostNet with hostnetwork",
  278. hasClusterDNS: true,
  279. hostNetwork: true,
  280. dnsPolicy: v1.DNSClusterFirstWithHostNet,
  281. expectedDNSType: podDNSCluster,
  282. },
  283. {
  284. desc: "valid DNSClusterFirstWithHostNet without hostnetwork",
  285. hasClusterDNS: true,
  286. dnsPolicy: v1.DNSClusterFirstWithHostNet,
  287. expectedDNSType: podDNSCluster,
  288. },
  289. {
  290. desc: "valid DNSDefault without hostnetwork",
  291. dnsPolicy: v1.DNSDefault,
  292. expectedDNSType: podDNSHost,
  293. },
  294. {
  295. desc: "valid DNSDefault with hostnetwork",
  296. hostNetwork: true,
  297. dnsPolicy: v1.DNSDefault,
  298. expectedDNSType: podDNSHost,
  299. },
  300. {
  301. desc: "DNSClusterFirst with hostnetwork, fallback to DNSDefault",
  302. hasClusterDNS: true,
  303. hostNetwork: true,
  304. dnsPolicy: v1.DNSClusterFirst,
  305. expectedDNSType: podDNSHost,
  306. },
  307. {
  308. desc: "valid DNSNone",
  309. dnsPolicy: v1.DNSNone,
  310. expectedDNSType: podDNSNone,
  311. },
  312. {
  313. desc: "invalid DNS policy, should return error",
  314. dnsPolicy: "invalidPolicy",
  315. expectedError: true,
  316. },
  317. }
  318. for _, tc := range testCases {
  319. t.Run(tc.desc, func(t *testing.T) {
  320. if tc.hasClusterDNS {
  321. configurer.clusterDNS = testClusterDNS
  322. } else {
  323. configurer.clusterDNS = nil
  324. }
  325. pod.Spec.DNSPolicy = tc.dnsPolicy
  326. pod.Spec.HostNetwork = tc.hostNetwork
  327. resType, err := getPodDNSType(pod)
  328. if tc.expectedError {
  329. if err == nil {
  330. t.Errorf("%s: GetPodDNSType(%v) got no error, want error", tc.desc, pod)
  331. }
  332. return
  333. }
  334. if resType != tc.expectedDNSType {
  335. t.Errorf("%s: GetPodDNSType(%v)=%v, want %v", tc.desc, pod, resType, tc.expectedDNSType)
  336. }
  337. })
  338. }
  339. }
  340. func TestGetPodDNS(t *testing.T) {
  341. recorder := record.NewFakeRecorder(20)
  342. nodeRef := &v1.ObjectReference{
  343. Kind: "Node",
  344. Name: string("testNode"),
  345. UID: types.UID("testNode"),
  346. Namespace: "",
  347. }
  348. clusterNS := "203.0.113.1"
  349. testClusterDNSDomain := "kubernetes.io"
  350. testClusterDNS := []net.IP{net.ParseIP(clusterNS)}
  351. configurer := NewConfigurer(recorder, nodeRef, nil, testClusterDNS, testClusterDNSDomain, "")
  352. pods := newTestPods(4)
  353. pods[0].Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
  354. pods[1].Spec.DNSPolicy = v1.DNSClusterFirst
  355. pods[2].Spec.DNSPolicy = v1.DNSClusterFirst
  356. pods[2].Spec.HostNetwork = false
  357. pods[3].Spec.DNSPolicy = v1.DNSDefault
  358. options := make([]struct {
  359. DNS []string
  360. DNSSearch []string
  361. }, 4)
  362. for i, pod := range pods {
  363. var err error
  364. dnsConfig, err := configurer.GetPodDNS(pod)
  365. if err != nil {
  366. t.Fatalf("failed to generate container options: %v", err)
  367. }
  368. options[i].DNS, options[i].DNSSearch = dnsConfig.Servers, dnsConfig.Searches
  369. }
  370. if len(options[0].DNS) != 1 || options[0].DNS[0] != clusterNS {
  371. t.Errorf("expected nameserver %s, got %+v", clusterNS, options[0].DNS)
  372. }
  373. if len(options[0].DNSSearch) == 0 || options[0].DNSSearch[0] != ".svc."+configurer.ClusterDomain {
  374. t.Errorf("expected search %s, got %+v", ".svc."+configurer.ClusterDomain, options[0].DNSSearch)
  375. }
  376. if len(options[1].DNS) != 1 || options[1].DNS[0] != "127.0.0.1" {
  377. t.Errorf("expected nameserver 127.0.0.1, got %+v", options[1].DNS)
  378. }
  379. if len(options[1].DNSSearch) != 1 || options[1].DNSSearch[0] != "." {
  380. t.Errorf("expected search \".\", got %+v", options[1].DNSSearch)
  381. }
  382. if len(options[2].DNS) != 1 || options[2].DNS[0] != clusterNS {
  383. t.Errorf("expected nameserver %s, got %+v", clusterNS, options[2].DNS)
  384. }
  385. if len(options[2].DNSSearch) == 0 || options[2].DNSSearch[0] != ".svc."+configurer.ClusterDomain {
  386. t.Errorf("expected search %s, got %+v", ".svc."+configurer.ClusterDomain, options[2].DNSSearch)
  387. }
  388. if len(options[3].DNS) != 1 || options[3].DNS[0] != "127.0.0.1" {
  389. t.Errorf("expected nameserver 127.0.0.1, got %+v", options[3].DNS)
  390. }
  391. if len(options[3].DNSSearch) != 1 || options[3].DNSSearch[0] != "." {
  392. t.Errorf("expected search \".\", got %+v", options[3].DNSSearch)
  393. }
  394. testResolverConfig := "/etc/resolv.conf"
  395. configurer = NewConfigurer(recorder, nodeRef, nil, testClusterDNS, testClusterDNSDomain, testResolverConfig)
  396. for i, pod := range pods {
  397. var err error
  398. dnsConfig, err := configurer.GetPodDNS(pod)
  399. if err != nil {
  400. t.Fatalf("failed to generate container options: %v", err)
  401. }
  402. options[i].DNS, options[i].DNSSearch = dnsConfig.Servers, dnsConfig.Searches
  403. }
  404. t.Logf("nameservers %+v", options[1].DNS)
  405. if len(options[0].DNS) != 1 {
  406. t.Errorf("expected cluster nameserver only, got %+v", options[0].DNS)
  407. } else if options[0].DNS[0] != clusterNS {
  408. t.Errorf("expected nameserver %s, got %v", clusterNS, options[0].DNS[0])
  409. }
  410. expLength := len(options[1].DNSSearch) + 3
  411. if expLength > 6 {
  412. expLength = 6
  413. }
  414. if len(options[0].DNSSearch) != expLength {
  415. t.Errorf("expected prepend of cluster domain, got %+v", options[0].DNSSearch)
  416. } else if options[0].DNSSearch[0] != ".svc."+configurer.ClusterDomain {
  417. t.Errorf("expected domain %s, got %s", ".svc."+configurer.ClusterDomain, options[0].DNSSearch)
  418. }
  419. if len(options[2].DNS) != 1 {
  420. t.Errorf("expected cluster nameserver only, got %+v", options[2].DNS)
  421. } else if options[2].DNS[0] != clusterNS {
  422. t.Errorf("expected nameserver %s, got %v", clusterNS, options[2].DNS[0])
  423. }
  424. if len(options[2].DNSSearch) != expLength {
  425. t.Errorf("expected prepend of cluster domain, got %+v", options[2].DNSSearch)
  426. } else if options[2].DNSSearch[0] != ".svc."+configurer.ClusterDomain {
  427. t.Errorf("expected domain %s, got %s", ".svc."+configurer.ClusterDomain, options[0].DNSSearch)
  428. }
  429. }
  430. func TestGetPodDNSCustom(t *testing.T) {
  431. recorder := record.NewFakeRecorder(20)
  432. nodeRef := &v1.ObjectReference{
  433. Kind: "Node",
  434. Name: string("testNode"),
  435. UID: types.UID("testNode"),
  436. Namespace: "",
  437. }
  438. testPodNamespace := "testNS"
  439. testClusterNameserver := "10.0.0.10"
  440. testClusterDNSDomain := "kubernetes.io"
  441. testSvcDomain := fmt.Sprintf("svc.%s", testClusterDNSDomain)
  442. testNsSvcDomain := fmt.Sprintf("%s.svc.%s", testPodNamespace, testClusterDNSDomain)
  443. testNdotsOptionValue := "3"
  444. testHostNameserver := "8.8.8.8"
  445. testHostDomain := "host.domain"
  446. testPod := &v1.Pod{
  447. ObjectMeta: metav1.ObjectMeta{
  448. Name: "test_pod",
  449. Namespace: testPodNamespace,
  450. },
  451. }
  452. resolvConfContent := []byte(fmt.Sprintf("nameserver %s\nsearch %s\n", testHostNameserver, testHostDomain))
  453. tmpfile, err := ioutil.TempFile("", "tmpResolvConf")
  454. if err != nil {
  455. t.Fatal(err)
  456. }
  457. defer os.Remove(tmpfile.Name())
  458. if _, err := tmpfile.Write(resolvConfContent); err != nil {
  459. t.Fatal(err)
  460. }
  461. if err := tmpfile.Close(); err != nil {
  462. t.Fatal(err)
  463. }
  464. configurer := NewConfigurer(recorder, nodeRef, nil, []net.IP{net.ParseIP(testClusterNameserver)}, testClusterDNSDomain, tmpfile.Name())
  465. testCases := []struct {
  466. desc string
  467. hostnetwork bool
  468. dnsPolicy v1.DNSPolicy
  469. dnsConfig *v1.PodDNSConfig
  470. expectedDNSConfig *runtimeapi.DNSConfig
  471. }{
  472. {
  473. desc: "DNSNone without DNSConfig should have empty DNS settings",
  474. dnsPolicy: v1.DNSNone,
  475. expectedDNSConfig: &runtimeapi.DNSConfig{},
  476. },
  477. {
  478. desc: "DNSNone with DNSConfig should have a merged DNS settings",
  479. dnsPolicy: v1.DNSNone,
  480. dnsConfig: &v1.PodDNSConfig{
  481. Nameservers: []string{"203.0.113.1"},
  482. Searches: []string{"my.domain", "second.domain"},
  483. Options: []v1.PodDNSConfigOption{
  484. {Name: "ndots", Value: &testNdotsOptionValue},
  485. {Name: "debug"},
  486. },
  487. },
  488. expectedDNSConfig: &runtimeapi.DNSConfig{
  489. Servers: []string{"203.0.113.1"},
  490. Searches: []string{"my.domain", "second.domain"},
  491. Options: []string{"ndots:3", "debug"},
  492. },
  493. },
  494. {
  495. desc: "DNSClusterFirst with DNSConfig should have a merged DNS settings",
  496. dnsPolicy: v1.DNSClusterFirst,
  497. dnsConfig: &v1.PodDNSConfig{
  498. Nameservers: []string{"10.0.0.11"},
  499. Searches: []string{"my.domain"},
  500. Options: []v1.PodDNSConfigOption{
  501. {Name: "ndots", Value: &testNdotsOptionValue},
  502. {Name: "debug"},
  503. },
  504. },
  505. expectedDNSConfig: &runtimeapi.DNSConfig{
  506. Servers: []string{testClusterNameserver, "10.0.0.11"},
  507. Searches: []string{testNsSvcDomain, testSvcDomain, testClusterDNSDomain, testHostDomain, "my.domain"},
  508. Options: []string{"ndots:3", "debug"},
  509. },
  510. },
  511. {
  512. desc: "DNSClusterFirstWithHostNet with DNSConfig should have a merged DNS settings",
  513. hostnetwork: true,
  514. dnsPolicy: v1.DNSClusterFirstWithHostNet,
  515. dnsConfig: &v1.PodDNSConfig{
  516. Nameservers: []string{"10.0.0.11"},
  517. Searches: []string{"my.domain"},
  518. Options: []v1.PodDNSConfigOption{
  519. {Name: "ndots", Value: &testNdotsOptionValue},
  520. {Name: "debug"},
  521. },
  522. },
  523. expectedDNSConfig: &runtimeapi.DNSConfig{
  524. Servers: []string{testClusterNameserver, "10.0.0.11"},
  525. Searches: []string{testNsSvcDomain, testSvcDomain, testClusterDNSDomain, testHostDomain, "my.domain"},
  526. Options: []string{"ndots:3", "debug"},
  527. },
  528. },
  529. {
  530. desc: "DNSDefault with DNSConfig should have a merged DNS settings",
  531. dnsPolicy: v1.DNSDefault,
  532. dnsConfig: &v1.PodDNSConfig{
  533. Nameservers: []string{"10.0.0.11"},
  534. Searches: []string{"my.domain"},
  535. Options: []v1.PodDNSConfigOption{
  536. {Name: "ndots", Value: &testNdotsOptionValue},
  537. {Name: "debug"},
  538. },
  539. },
  540. expectedDNSConfig: &runtimeapi.DNSConfig{
  541. Servers: []string{testHostNameserver, "10.0.0.11"},
  542. Searches: []string{testHostDomain, "my.domain"},
  543. Options: []string{"ndots:3", "debug"},
  544. },
  545. },
  546. }
  547. for _, tc := range testCases {
  548. t.Run(tc.desc, func(t *testing.T) {
  549. testPod.Spec.HostNetwork = tc.hostnetwork
  550. testPod.Spec.DNSConfig = tc.dnsConfig
  551. testPod.Spec.DNSPolicy = tc.dnsPolicy
  552. resDNSConfig, err := configurer.GetPodDNS(testPod)
  553. if err != nil {
  554. t.Errorf("%s: GetPodDNS(%v), unexpected error: %v", tc.desc, testPod, err)
  555. }
  556. if !dnsConfigsAreEqual(resDNSConfig, tc.expectedDNSConfig) {
  557. t.Errorf("%s: GetPodDNS(%v)=%v, want %v", tc.desc, testPod, resDNSConfig, tc.expectedDNSConfig)
  558. }
  559. })
  560. }
  561. }
  562. func dnsConfigsAreEqual(resConfig, expectedConfig *runtimeapi.DNSConfig) bool {
  563. if len(resConfig.Servers) != len(expectedConfig.Servers) ||
  564. len(resConfig.Searches) != len(expectedConfig.Searches) ||
  565. len(resConfig.Options) != len(expectedConfig.Options) {
  566. return false
  567. }
  568. for i, server := range resConfig.Servers {
  569. if expectedConfig.Servers[i] != server {
  570. return false
  571. }
  572. }
  573. for i, search := range resConfig.Searches {
  574. if expectedConfig.Searches[i] != search {
  575. return false
  576. }
  577. }
  578. // Options order may be changed after conversion.
  579. return sets.NewString(resConfig.Options...).Equal(sets.NewString(expectedConfig.Options...))
  580. }
  581. func newTestPods(count int) []*v1.Pod {
  582. pods := make([]*v1.Pod, count)
  583. for i := 0; i < count; i++ {
  584. pods[i] = &v1.Pod{
  585. Spec: v1.PodSpec{
  586. HostNetwork: true,
  587. },
  588. ObjectMeta: metav1.ObjectMeta{
  589. UID: types.UID(10000 + i),
  590. Name: fmt.Sprintf("pod%d", i),
  591. },
  592. }
  593. }
  594. return pods
  595. }