aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/dnsserver/zdirectives.go2
-rw-r--r--middleware.cfg10
-rw-r--r--middleware/kubernetes/handler.go3
-rw-r--r--middleware/kubernetes/kubernetes.go1
-rw-r--r--middleware/kubernetes/setup.go7
-rw-r--r--middleware/kubernetes/setup_test.go49
-rw-r--r--test/kubernetes_test.go59
7 files changed, 122 insertions, 9 deletions
diff --git a/core/dnsserver/zdirectives.go b/core/dnsserver/zdirectives.go
index 7be013e17..d23862a82 100644
--- a/core/dnsserver/zdirectives.go
+++ b/core/dnsserver/zdirectives.go
@@ -26,11 +26,11 @@ var directives = []string{
"loadbalance",
"dnssec",
"reverse",
+ "kubernetes",
"file",
"auto",
"secondary",
"etcd",
- "kubernetes",
"proxy",
"whoami",
"erratic",
diff --git a/middleware.cfg b/middleware.cfg
index 6695718a2..909ba104f 100644
--- a/middleware.cfg
+++ b/middleware.cfg
@@ -34,11 +34,11 @@
120:loadbalance:loadbalance
130:dnssec:dnssec
140:reverse:reverse
-150:file:file
-160:auto:auto
-170:secondary:secondary
-180:etcd:etcd
-190:kubernetes:kubernetes
+150:kubernetes:kubernetes
+160:file:file
+170:auto:auto
+180:secondary:secondary
+190:etcd:etcd
200:proxy:proxy
210:whoami:whoami
220:erratic:erratic
diff --git a/middleware/kubernetes/handler.go b/middleware/kubernetes/handler.go
index 9dfc5c5a0..6eb637506 100644
--- a/middleware/kubernetes/handler.go
+++ b/middleware/kubernetes/handler.go
@@ -71,6 +71,9 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
_, _, err = middleware.A(&k, zone, state, nil, middleware.Options{})
}
if k.IsNameError(err) {
+ if k.Fallthrough {
+ return middleware.NextOrFailure(k.Name(), k.Next, ctx, w, r)
+ }
// Make err nil when returning here, so we don't log spam for NXDOMAIN.
return middleware.BackendError(&k, zone, dns.RcodeNameError, state, nil /*debug*/, nil /* err */, middleware.Options{})
}
diff --git a/middleware/kubernetes/kubernetes.go b/middleware/kubernetes/kubernetes.go
index ca2d69824..82bbcbce3 100644
--- a/middleware/kubernetes/kubernetes.go
+++ b/middleware/kubernetes/kubernetes.go
@@ -43,6 +43,7 @@ type Kubernetes struct {
Selector *labels.Selector
PodMode string
ReverseCidrs []net.IPNet
+ Fallthrough bool
}
const (
diff --git a/middleware/kubernetes/setup.go b/middleware/kubernetes/setup.go
index be045a522..9467d1d28 100644
--- a/middleware/kubernetes/setup.go
+++ b/middleware/kubernetes/setup.go
@@ -155,6 +155,13 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
continue
}
return nil, c.ArgErr()
+ case "fallthrough":
+ args := c.RemainingArgs()
+ if len(args) == 0 {
+ k8s.Fallthrough = true
+ continue
+ }
+ return nil, c.ArgErr()
}
}
return k8s, nil
diff --git a/middleware/kubernetes/setup_test.go b/middleware/kubernetes/setup_test.go
index bc6418c0d..f9a87a805 100644
--- a/middleware/kubernetes/setup_test.go
+++ b/middleware/kubernetes/setup_test.go
@@ -27,6 +27,7 @@ func TestKubernetesParse(t *testing.T) {
expectedLabelSelector string // expected label selector value
expectedPodMode string
expectedCidrs []net.IPNet
+ expectedFallthrough bool
}{
// positive
{
@@ -40,6 +41,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"kubernetes keyword with multiple zones",
@@ -52,6 +54,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"kubernetes keyword with zone and empty braces",
@@ -65,6 +68,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"endpoint keyword with url",
@@ -79,6 +83,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"namespaces keyword with one namespace",
@@ -93,6 +98,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"namespaces keyword with multiple namespaces",
@@ -107,6 +113,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"resync period in seconds",
@@ -121,6 +128,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"resync period in minutes",
@@ -135,6 +143,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"basic label selector",
@@ -149,6 +158,7 @@ func TestKubernetesParse(t *testing.T) {
"environment=prod",
defaultPodMode,
nil,
+ false,
},
{
"multi-label selector",
@@ -163,6 +173,7 @@ func TestKubernetesParse(t *testing.T) {
"application=nginx,environment in (production,qa,staging)",
defaultPodMode,
nil,
+ false,
},
{
"fully specified valid config",
@@ -171,6 +182,7 @@ func TestKubernetesParse(t *testing.T) {
endpoint http://localhost:8080
namespaces demo test
labels environment in (production, staging, qa),application=nginx
+ fallthrough
}`,
false,
"",
@@ -180,6 +192,7 @@ func TestKubernetesParse(t *testing.T) {
"application=nginx,environment in (production,qa,staging)",
defaultPodMode,
nil,
+ true,
},
// negative
{
@@ -193,6 +206,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"kubernetes keyword without a zone",
@@ -205,6 +219,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"endpoint keyword without an endpoint value",
@@ -219,6 +234,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"namespace keyword without a namespace value",
@@ -233,6 +249,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"resyncperiod keyword without a duration value",
@@ -247,6 +264,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"resync period no units",
@@ -261,6 +279,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"resync period invalid",
@@ -275,6 +294,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"labels with no selector value",
@@ -289,6 +309,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
{
"labels with invalid selector value",
@@ -303,6 +324,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
},
// pods disabled
{
@@ -318,6 +340,7 @@ func TestKubernetesParse(t *testing.T) {
"",
PodModeDisabled,
nil,
+ false,
},
// pods insecure
{
@@ -333,6 +356,7 @@ func TestKubernetesParse(t *testing.T) {
"",
PodModeInsecure,
nil,
+ false,
},
// pods verified
{
@@ -348,6 +372,7 @@ func TestKubernetesParse(t *testing.T) {
"",
PodModeVerified,
nil,
+ false,
},
// pods invalid
{
@@ -363,6 +388,7 @@ func TestKubernetesParse(t *testing.T) {
"",
PodModeVerified,
nil,
+ false,
},
// cidrs ok
{
@@ -378,6 +404,7 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
[]net.IPNet{parseCidr("10.0.0.0/24"), parseCidr("10.0.1.0/24")},
+ false,
},
// cidrs ok
{
@@ -393,6 +420,23 @@ func TestKubernetesParse(t *testing.T) {
"",
defaultPodMode,
nil,
+ false,
+ },
+ // fallthrough invalid
+ {
+ "Extra params for fallthrough",
+ `kubernetes coredns.local {
+ fallthrough junk
+}`,
+ true,
+ "Wrong argument count",
+ -1,
+ 0,
+ defaultResyncPeriod,
+ "",
+ defaultPodMode,
+ nil,
+ false,
},
}
@@ -466,6 +510,11 @@ func TestKubernetesParse(t *testing.T) {
t.Errorf("Test %d: Expected kubernetes controller to be initialized with cidr '%s'. Instead found cidr '%s' for input '%s'", i, test.expectedCidrs[j].String(), foundCidrs[j].String(), test.input)
}
}
+ // fallthrough
+ foundFallthrough := k8sController.Fallthrough
+ if foundFallthrough != test.expectedFallthrough {
+ t.Errorf("Test %d: Expected kubernetes controller to be initialized with fallthrough '%v'. Instead found fallthrough '%v' for input '%s'", i, test.expectedFallthrough, foundFallthrough, test.input)
+ }
}
}
diff --git a/test/kubernetes_test.go b/test/kubernetes_test.go
index 54d346ad5..4ef4e18ec 100644
--- a/test/kubernetes_test.go
+++ b/test/kubernetes_test.go
@@ -3,6 +3,7 @@
package test
import (
+ "os"
"testing"
"time"
@@ -372,6 +373,23 @@ var dnsTestCasesAllNSExposed = []test.Case{
},
}
+var dnsTestCasesFallthrough = []test.Case{
+ {
+ 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"),
+ },
+ },
+ {
+ Qname: "foo.cluster.local.", Qtype: dns.TypeA,
+ Rcode: dns.RcodeSuccess,
+ Answer: []dns.RR{
+ test.A("foo.cluster.local. 303 IN A 10.10.10.10"),
+ },
+ },
+}
+
func createTestServer(t *testing.T, corefile string) (*caddy.Instance, string) {
server, err := CoreDNSServer(corefile)
if err != nil {
@@ -424,9 +442,6 @@ func TestKubernetesIntegration(t *testing.T) {
`.:0 {
kubernetes cluster.local 0.0.10.in-addr.arpa {
endpoint http://localhost:8080
- #endpoint https://kubernetes/
- #tls admin.pem admin-key.pem ca.pem
- #tls k8s_auth/client2.crt k8s_auth/client2.key k8s_auth/ca2.crt
namespaces test-1
pods disabled
}
@@ -501,3 +516,41 @@ func TestKubernetesIntegrationAllNSExposed(t *testing.T) {
`
doIntegrationTests(t, corefile, dnsTestCasesAllNSExposed)
}
+
+func TestKubernetesIntegrationFallthrough(t *testing.T) {
+ dbfile, rmFunc, err := TempFile(os.TempDir(), clusterLocal)
+ if err != nil {
+ t.Fatalf("Could not create TempFile for fallthrough: %s", err)
+ }
+ defer rmFunc()
+ corefile :=
+ `.:0 {
+ file ` + dbfile + ` cluster.local
+ kubernetes cluster.local {
+ endpoint http://localhost:8080
+ cidrs 10.0.0.0/24
+ namespaces test-1
+ fallthrough
+ }
+ erratic {
+ drop 0
+ }
+`
+ cases := append(dnsTestCases, dnsTestCasesFallthrough...)
+ doIntegrationTests(t, corefile, cases)
+}
+
+const clusterLocal = `; cluster.local test file for fallthrough
+cluster.local. IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600
+cluster.local. IN NS b.iana-servers.net.
+cluster.local. IN NS a.iana-servers.net.
+cluster.local. IN A 127.0.0.1
+cluster.local. IN A 127.0.0.2
+foo.cluster.local. IN A 10.10.10.10
+f.b.svc.cluster.local. IN A 10.10.10.11
+*.w.cluster.local. IN TXT "Wildcard"
+a.b.svc.cluster.local. IN TXT "Not a wildcard"
+cname.cluster.local. IN CNAME www.example.net.
+
+service.namespace.svc.cluster.local. IN SRV 8080 10 10 cluster.local.
+`