diff --git a/.travis.yml b/.travis.yml index c55b23ab9..60410e045 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ env: # IPv6 is needed by some of the CoreDNS test cases. The VM environment # is needed to have access to sudo in the test environment. Sudo is # needed to have docker in the test environment. Docker is needed to -# launch a kubernetes instance in the test environment. +# launch a Kubernetes instance in the test environment. # (Dependencies are fun! :) ) before_install: - cat /proc/net/if_inet6 @@ -51,5 +51,6 @@ before_script: script: - make TEST_TYPE=$TEST_TYPE travis + after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/middleware/kubernetes/handler_test.go b/middleware/kubernetes/handler_test.go index 292ffdf3a..d5345215d 100644 --- a/middleware/kubernetes/handler_test.go +++ b/middleware/kubernetes/handler_test.go @@ -235,19 +235,8 @@ func runServeDNSTests(ctx context.Context, t *testing.T, dnsTestCases map[string } // Before sorting, make sure that CNAMES do not appear after their target records - for i, c := range resp.Answer { - if c.Header().Rrtype != dns.TypeCNAME { - continue - } - for _, a := range resp.Answer[:i] { - if a.Header().Name != c.(*dns.CNAME).Target { - continue - } - t.Errorf("%v: CNAME found after target record\n", testname) - t.Logf("%v Received:\n %v\n", testname, resp) + test.CNAMEOrder(t, resp) - } - } test.SortAndCheck(t, resp, tc) } } diff --git a/middleware/test/helpers.go b/middleware/test/helpers.go index 2074f46c2..35316dd38 100644 --- a/middleware/test/helpers.go +++ b/middleware/test/helpers.go @@ -13,7 +13,7 @@ type sect int const ( // Answer is the answer section in an Msg. Answer sect = iota - // Ns is the authrotitative section in an Msg. + // Ns is the authoritative section in an Msg. Ns // Extra is the additional section in an Msg. Extra @@ -264,6 +264,23 @@ func Section(t *testing.T, tc Case, sec sect, rr []dns.RR) bool { return true } +// CNAMEOrder makes sure that CNAMES do not appear after their target records +func CNAMEOrder(t *testing.T, res *dns.Msg) { + for i, c := range res.Answer { + if c.Header().Rrtype != dns.TypeCNAME { + continue + } + for _, a := range res.Answer[:i] { + if a.Header().Name != c.(*dns.CNAME).Target { + continue + } + t.Errorf("CNAME found after target record\n") + t.Logf("%v\n", res) + + } + } +} + // SortAndCheck sorts resp and the checks the header and three sections against the testcase in tc. func SortAndCheck(t *testing.T, resp *dns.Msg, tc Case) { sort.Sort(RRSet(resp.Answer)) diff --git a/test/kubernetes_test.go b/test/kubernetes_test.go index 881394c00..2e7207da2 100644 --- a/test/kubernetes_test.go +++ b/test/kubernetes_test.go @@ -6,6 +6,10 @@ import ( "io/ioutil" "log" "os" + "os/exec" + "sort" + "strconv" + "strings" "testing" "time" @@ -20,7 +24,6 @@ func init() { } // Test data -// TODO: Fix the actual RR values var dnsTestCases = []test.Case{ { @@ -34,197 +37,241 @@ var dnsTestCases = []test.Case{ Qname: "bogusservice.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "bogusendpoint.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "bogusendpoint.headless-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-a.*.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { Qname: "svc-1-a.any.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-a.any.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { Qname: "bogusservice.*.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "bogusservice.any.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), - test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), - test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.5"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.6"), - test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), - test.A("example.net. 68974 IN A 13.14.15.16"), - }, + Answer: append([]dns.RR{ + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("*.test-1.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("*.test-1.svc.cluster.local.", "headless-svc", "test-1")...), }, { Qname: "any.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), - test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), - test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.5"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.6"), - test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), - test.A("example.net. 68974 IN A 13.14.15.16"), - }, + Answer: append([]dns.RR{ + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("any.test-1.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("any.test-1.svc.cluster.local.", "headless-svc", "test-1")...), }, { Qname: "any.test-2.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.test-2.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.*.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), - test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), - test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.5"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.6"), - test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), - test.A("example.net. 68974 IN A 13.14.15.16"), - }, + Answer: append([]dns.RR{ + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("*.*.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("*.*.svc.cluster.local.", "headless-svc", "test-1")...), }, { Qname: "headless-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, - Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.5"), - test.A("headless-svc.test-1.svc.cluster.local. 303 IN A 172.17.0.6"), - }, + Rcode: dns.RcodeSuccess, + Answer: headlessAResponse("headless-svc.test-1.svc.cluster.local.", "headless-svc", "test-1"), }, { Qname: "*._TcP.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_https._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._TcP.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._TcP.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { Qname: "*.*.bogusservice.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.any.svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_https._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*.any.svc-1-a.*.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*.any.svc-1-a.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { Qname: "ANY.*.svc-1-a.any.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_https._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("ANY.*.svc-1-a.any.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("ANY.*.svc-1-a.any.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { Qname: "*.*.bogusservice.*.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.*.bogusservice.any.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "_c-port._UDP.*.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.SRV("_c-port._udp.svc-c.test-1.svc.cluster.local. 303 IN SRV 10 100 1234 svc-c.test-1.svc.cluster.local."), - test.SRV("_c-port._udp.headless-svc.test-1.svc.cluster.local. 303 IN SRV 10 100 1234 172-17-0-5.headless-svc.test-1.svc.cluster.local."), - test.SRV("_c-port._udp.headless-svc.test-1.svc.cluster.local. 303 IN SRV 10 100 1234 172-17-0-6.headless-svc.test-1.svc.cluster.local."), - }, + Answer: append(srvResponse("_c-port._UDP.*.test-1.svc.cluster.local.", "TypeSRV", "headless-svc", "test-1"), + []dns.RR{ + test.SRV("_c-port._UDP.*.test-1.svc.cluster.local. 303 IN SRV 0 33 1234 svc-c.test-1.svc.cluster.local.")}...), + Extra: append(srvResponse("_c-port._UDP.*.test-1.svc.cluster.local.", "TypeA", "headless-svc", "test-1"), + []dns.RR{ + test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.115")}...), }, { Qname: "*._tcp.any.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_https._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 443 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_http._tcp.svc-1-b.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-b.test-1.svc.cluster.local."), + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 80 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 80 svc-1-b.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), }, }, { Qname: "*.*.any.test-2.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "*.*.*.test-2.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), + }, }, { Qname: "_http._tcp.*.*.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_http._tcp.svc-1-b.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-b.test-1.svc.cluster.local."), + test.SRV("_http._tcp.*.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + test.SRV("_http._tcp.*.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-b.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), }, }, { Qname: "*.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, - Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.SRV("*.svc-1-a.test-1.svc.cluster.local. 0 IN SRV 0 50 443 172-17-0-7.svc-1-a.test-1.svc.cluster.local."), - test.SRV("*.svc-1-a.test-1.svc.cluster.local. 0 IN SRV 0 50 80 172-17-0-7.svc-1-a.test-1.svc.cluster.local."), - }, - Extra: []dns.RR{ - test.A("172-17-0-7.svc-1-a.test-1.svc.cluster.local. 0 IN A 172.17.0.7"), - }, + Rcode: dns.RcodeSuccess, + Answer: srvResponse("*.svc-1-a.test-1.svc.cluster.local.", "TypeSRV", "svc-1-a", "test-1"), + Extra: srvResponse("*.svc-1-a.test-1.svc.cluster.local.", "TypeA", "svc-1-a", "test-1"), }, { Qname: "*._not-udp-or-tcp.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, - Rcode: dns.RcodeNameError, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, Ns: []dns.RR{ - test.SOA("cluster.local. 300 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502313310 7200 1800 86400 60"), }, }, { Qname: "svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.SRV("_http._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 80 svc-1-a.test-1.svc.cluster.local."), - test.SRV("_https._tcp.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 10 100 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), }, }, { @@ -236,29 +283,22 @@ var dnsTestCases = []test.Case{ Qname: "dns-version.cluster.local.", Qtype: dns.TypeTXT, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.TXT("dns-version.cluster.local. 28800 IN TXT \"1.0.0\""), - }, - }, - { - Qname: "cluster.local.", Qtype: dns.TypeNS, - Rcode: dns.RcodeSuccess, - Answer: []dns.RR{ - test.NS("cluster.local. 0 IN NS kubernetes.default.svc.cluster.local."), + test.TXT(`dns-version.cluster.local. 303 IN TXT "1.0.1"`), }, }, { Qname: "ext-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), - test.A("example.net. 72031 IN A 13.14.15.16"), + test.A("example.net. 303 IN A 13.14.15.16"), + test.CNAME("ext-svc.test-1.svc.cluster.local. 303 IN CNAME example.net."), }, }, { Qname: "ext-svc.test-1.svc.cluster.local.", Qtype: dns.TypeCNAME, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), + test.CNAME("ext-svc.test-1.svc.cluster.local. 303 IN CNAME example.net."), }, }, } @@ -268,13 +308,16 @@ var dnsTestCasesPodsInsecure = []test.Case{ Qname: "10-20-0-101.test-1.pod.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.A("10-20-0-101.test-1.pod.cluster.local. 0 IN A 10.20.0.101"), + test.A("10-20-0-101.test-1.pod.cluster.local. 303 IN A 10.20.0.101"), }, }, { Qname: "10-20-0-101.test-X.pod.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502307903 7200 1800 86400 60"), + }, }, } @@ -283,11 +326,17 @@ var dnsTestCasesPodsVerified = []test.Case{ Qname: "10-20-0-101.test-1.pod.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502308197 7200 1800 86400 60"), + }, }, { Qname: "10-20-0-101.test-X.pod.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeNameError, Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1502307960 7200 1800 86400 60"), + }, }, } @@ -303,18 +352,300 @@ var dnsTestCasesAllNSExposed = []test.Case{ Qname: "svc-c.test-2.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ - test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.120"), + test.A("svc-c.test-2.svc.cluster.local. 303 IN A 10.0.0.120"), }, }, } var dnsTestCasesFallthrough = []test.Case{ + { + Qname: "svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "bogusservice.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "bogusendpoint.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "bogusendpoint.headless-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.A("svc-1-a.*.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "svc-1-a.any.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.A("svc-1-a.any.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "bogusservice.*.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "bogusservice.any.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: append([]dns.RR{ + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("*.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("*.test-1.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("*.test-1.svc.cluster.local.", "headless-svc", "test-1")...), + }, + { + Qname: "any.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: append([]dns.RR{ + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("any.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("any.test-1.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("any.test-1.svc.cluster.local.", "headless-svc", "test-1")...), + }, + { + Qname: "any.test-2.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.test-2.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.*.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: append([]dns.RR{ + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.110"), + test.A("*.*.svc.cluster.local. 303 IN A 10.0.0.115"), + test.CNAME("*.*.svc.cluster.local. 303 IN CNAME example.net."), + test.A("example.net. 303 IN A 13.14.15.16"), + }, headlessAResponse("*.*.svc.cluster.local.", "headless-svc", "test-1")...), + }, + { + Qname: "headless-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: headlessAResponse("headless-svc.test-1.svc.cluster.local.", "headless-svc", "test-1"), + }, + { + Qname: "*._TcP.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("*._TcP.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._TcP.svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "*.*.bogusservice.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.any.svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("*.any.svc-1-a.*.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*.any.svc-1-a.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "ANY.*.svc-1-a.any.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("ANY.*.svc-1-a.any.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("ANY.*.svc-1-a.any.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "*.*.bogusservice.*.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.*.bogusservice.any.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "_c-port._UDP.*.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: append(srvResponse("_c-port._UDP.*.test-1.svc.cluster.local.", "TypeSRV", "headless-svc", "test-1"), + []dns.RR{ + test.SRV("_c-port._UDP.*.test-1.svc.cluster.local. 303 IN SRV 0 33 1234 svc-c.test-1.svc.cluster.local."), + }...), + + Extra: append(srvResponse("_c-port._UDP.*.test-1.svc.cluster.local.", "TypeA", "headless-svc", "test-1"), + []dns.RR{ + test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.115"), + }...), + }, + { + Qname: "*._tcp.any.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 80 svc-1-a.test-1.svc.cluster.local."), + test.SRV("*._tcp.any.test-1.svc.cluster.local. 303 IN SRV 0 33 80 svc-1-b.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + }, + }, + { + Qname: "*.*.any.test-2.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "*.*.*.test-2.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "_http._tcp.*.*.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("_http._tcp.*.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + test.SRV("_http._tcp.*.*.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-b.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + test.A("svc-1-b.test-1.svc.cluster.local. 303 IN A 10.0.0.110"), + }, + }, + { + Qname: "*.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: srvResponse("*.svc-1-a.test-1.svc.cluster.local.", "TypeSRV", "svc-1-a", "test-1"), + Extra: srvResponse("*.svc-1-a.test-1.svc.cluster.local.", "TypeA", "svc-1-a", "test-1"), + }, + { + Qname: "*._not-udp-or-tcp.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeNameError, + Answer: []dns.RR{}, + Ns: []dns.RR{ + test.SOA("cluster.local. 303 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600"), + }, + }, + { + Qname: "svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeSRV, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.SRV("svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 443 svc-1-a.test-1.svc.cluster.local."), + test.SRV("svc-1-a.test-1.svc.cluster.local. 303 IN SRV 0 50 80 svc-1-a.test-1.svc.cluster.local."), + }, + Extra: []dns.RR{ + test.A("svc-1-a.test-1.svc.cluster.local. 303 IN A 10.0.0.100"), + }, + }, + { + Qname: "10-20-0-101.test-1.pod.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeServerFailure, + Answer: []dns.RR{}, + }, + { + Qname: "dns-version.cluster.local.", Qtype: dns.TypeTXT, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.TXT("dns-version.cluster.local. 28800 IN TXT \"1.0.1\""), + }, + }, + { + Qname: "ext-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.A("example.net. 303 IN A 13.14.15.16"), + test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), + }, + }, + { + Qname: "ext-svc.test-1.svc.cluster.local.", Qtype: dns.TypeCNAME, + Rcode: dns.RcodeSuccess, + Answer: []dns.RR{ + test.CNAME("ext-svc.test-1.svc.cluster.local. 0 IN CNAME example.net."), + }, + }, { Qname: "f.b.svc.cluster.local.", Qtype: dns.TypeA, Rcode: dns.RcodeSuccess, Answer: []dns.RR{ test.A("f.b.svc.cluster.local. 303 IN A 10.10.10.11"), }, + Ns: []dns.RR{ + test.NS("cluster.local. 303 IN NS a.iana-servers.net."), + test.NS("cluster.local. 303 IN NS b.iana-servers.net."), + }, }, { Qname: "foo.cluster.local.", Qtype: dns.TypeA, @@ -322,6 +653,10 @@ var dnsTestCasesFallthrough = []test.Case{ Answer: []dns.RR{ test.A("foo.cluster.local. 303 IN A 10.10.10.10"), }, + Ns: []dns.RR{ + test.NS("cluster.local. 303 IN NS a.iana-servers.net."), + test.NS("cluster.local. 303 IN NS b.iana-servers.net."), + }, }, } @@ -359,17 +694,18 @@ func doIntegrationTests(t *testing.T, corefile string, testCases []test.Case) { t.Fatalf("Could not send query: %s", err) } - // check the answer - if res.Rcode != tc.Rcode { - t.Errorf("Expected rcode %d but got %d for query %s, %d", tc.Rcode, res.Rcode, tc.Qname, tc.Qtype) - } + // Before sorting, make sure that CNAMES do not appear after their target records + test.CNAMEOrder(t, res) - if len(res.Answer) != len(tc.Answer) { - t.Errorf("Expected %d answers but got %d for query %s, %d\nfull reply %s", len(tc.Answer), len(res.Answer), tc.Qname, tc.Qtype, res) - } + // Sorting the test cases to check with the response + sort.Sort(test.RRSet(tc.Answer)) + sort.Sort(test.RRSet(tc.Ns)) + sort.Sort(test.RRSet(tc.Extra)) + + test.SortAndCheck(t, res, tc) - //TODO: Check the actual RR values } + } func createUpstreamServer(t *testing.T) (func(), *caddy.Instance, string) { @@ -487,8 +823,70 @@ func TestKubernetesIntegrationFallthrough(t *testing.T) { drop 0 } ` - cases := append(dnsTestCases, dnsTestCasesFallthrough...) - doIntegrationTests(t, corefile, cases) + doIntegrationTests(t, corefile, dnsTestCasesFallthrough) +} + +//headlessAResponse returns the answer to an A request for the specific name and namespace +func headlessAResponse(qname, namespace, name string) []dns.RR { + rr := []dns.RR{} + + str, err := endpointIPs(name, namespace) + if err != nil { + log.Fatal("Error running kubectl command: ", err.Error()) + } + result := strings.Split(string(str), " ") + lr := len(result) + + for i := 0; i < lr; i++ { + rr = append(rr, test.A(qname+" 303 IN A "+result[i])) + } + return rr +} + +// srvResponse returns the answer to a SRV request for the specific name and namespace +// responsetype is the type of answer to generate, eg: TypeSRV ( for answer section) or TypeA (for extra section) +func srvResponse(qname, responsetype, namespace, name string) []dns.RR { + rr := []dns.RR{} + + str, err := endpointIPs(name, namespace) + + if err != nil { + log.Fatal("Error running kubectl command: ", err.Error()) + } + result := strings.Split(string(str), " ") + lr := len(result) + + for i := 0; i < lr; i++ { + ip := strings.Replace(result[i], ".", "-", -1) + t := strconv.Itoa(100 / (lr + 1)) + if responsetype == "TypeA" { + rr = append(rr, test.A(ip+"."+namespace+"."+name+".svc.cluster.local. 0 IN A "+result[i])) + } + if responsetype == "TypeSRV" && namespace == "headless-svc" { + rr = append(rr, test.SRV(qname+" 303 IN SRV 0 "+t+" 1234 "+ip+"."+namespace+"."+name+".svc.cluster.local.")) + } + if responsetype == "TypeSRV" && namespace != "headless-svc" { + rr = append(rr, test.SRV(qname+" 303 IN SRV 0 "+t+" 443 "+ip+"."+namespace+"."+name+".svc.cluster.local.")) + rr = append(rr, test.SRV(qname+" 303 IN SRV 0 "+t+" 80 "+ip+"."+namespace+"."+name+".svc.cluster.local.")) + } + + } + return rr +} + +//endpointIPs retrieves the IP address for a given name and namespace by parsing json using kubectl command +func endpointIPs(name, namespace string) (cmdOut []byte, err error) { + + kctl := os.Getenv("KUBECTL") + + if kctl == "" { + kctl = "kubectl" + } + cmdArgs := kctl + " -n " + name + " get endpoints " + namespace + " -o jsonpath={.subsets[*].addresses[*].ip}" + if cmdOut, err = exec.Command("sh", "-c", cmdArgs).Output(); err != nil { + return nil, err + } + return cmdOut, nil } const clusterLocal = `; cluster.local test file for fallthrough