aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorGravatar John Belamaric <jbelamaric@infoblox.com> 2018-01-06 14:52:09 -0500
committerGravatar GitHub <noreply@github.com> 2018-01-06 14:52:09 -0500
commit84ebbbc7225a8d7eb5e00c0c525f7e12932a9fe4 (patch)
tree075407cf860a7e32c121dfc0d292fd389bf7a3c2 /plugin
parent75a8a17da4fc95c086dfb447d29c02e7dbd05561 (diff)
downloadcoredns-84ebbbc7225a8d7eb5e00c0c525f7e12932a9fe4.tar.gz
coredns-84ebbbc7225a8d7eb5e00c0c525f7e12932a9fe4.tar.zst
coredns-84ebbbc7225a8d7eb5e00c0c525f7e12932a9fe4.zip
kubernetes: Add zone filtering to fallthrough (#1353)
* Add zone filtering to fallthrough * Doh. gofmt * Update documentation
Diffstat (limited to 'plugin')
-rw-r--r--plugin/kubernetes/README.md11
-rw-r--r--plugin/kubernetes/handler.go2
-rw-r--r--plugin/kubernetes/kubernetes.go2
-rw-r--r--plugin/kubernetes/setup.go8
-rw-r--r--plugin/kubernetes/setup_test.go78
-rw-r--r--plugin/plugin.go15
-rw-r--r--plugin/plugin_test.go20
7 files changed, 92 insertions, 44 deletions
diff --git a/plugin/kubernetes/README.md b/plugin/kubernetes/README.md
index 5c3e8e92f..a5a6d8236 100644
--- a/plugin/kubernetes/README.md
+++ b/plugin/kubernetes/README.md
@@ -38,7 +38,7 @@ kubernetes [ZONES...] {
endpoint_pod_names
upstream ADDRESS...
ttl TTL
- fallthrough
+ fallthrough [ZONES...]
}
```
@@ -85,9 +85,12 @@ kubernetes [ZONES...] {
to a file structured like resolv.conf.
* `ttl` allows you to set a custom TTL for responses. The default (and allowed minimum) is to use
5 seconds, the maximum is capped at 3600 seconds.
-* `fallthrough` If a query for a record in the cluster zone results in NXDOMAIN, normally that is
- what the response will be. However, if you specify this option, the query will instead be passed
- on down the plugin chain, which can include another plugin to handle the query.
+* `fallthrough` **[ZONES...]** If a query for a record in the zones for which the plugin is authoritative
+ results in NXDOMAIN, normally that is what the response will be. However, if you specify this option,
+ the query will instead be passed on down the plugin chain, which can include another plugin to handle
+ the query. If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
+ is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
+ queries for those zones will be subject to fallthrough.
## Health
diff --git a/plugin/kubernetes/handler.go b/plugin/kubernetes/handler.go
index f61bb69b1..4606e3747 100644
--- a/plugin/kubernetes/handler.go
+++ b/plugin/kubernetes/handler.go
@@ -59,7 +59,7 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
}
if k.IsNameError(err) {
- if k.Fallthrough {
+ if plugin.Fallthrough(k.Fallthrough, state.Name()) {
return plugin.NextOrFailure(k.Name(), k.Next, ctx, w, r)
}
return plugin.BackendError(&k, zone, dns.RcodeNameError, state, nil /* err */, plugin.Options{})
diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go
index 785a16ae3..66821380e 100644
--- a/plugin/kubernetes/kubernetes.go
+++ b/plugin/kubernetes/kubernetes.go
@@ -40,7 +40,7 @@ type Kubernetes struct {
Namespaces map[string]bool
podMode string
endpointNameMode bool
- Fallthrough bool
+ Fallthrough *[]string // nil = disabled, empty = all zones, o/w zones
ttl uint32
primaryZoneIndex int
diff --git a/plugin/kubernetes/setup.go b/plugin/kubernetes/setup.go
index fd63d6ff6..41727cb7e 100644
--- a/plugin/kubernetes/setup.go
+++ b/plugin/kubernetes/setup.go
@@ -172,12 +172,8 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, dnsControlOpts, error) {
}
return nil, opts, c.ArgErr()
case "fallthrough":
- args := c.RemainingArgs()
- if len(args) == 0 {
- k8s.Fallthrough = true
- continue
- }
- return nil, opts, c.ArgErr()
+ zones := c.RemainingArgs()
+ k8s.Fallthrough = &zones
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
diff --git a/plugin/kubernetes/setup_test.go b/plugin/kubernetes/setup_test.go
index 224c168a1..6f726c7c4 100644
--- a/plugin/kubernetes/setup_test.go
+++ b/plugin/kubernetes/setup_test.go
@@ -19,7 +19,7 @@ func TestKubernetesParse(t *testing.T) {
expectedResyncPeriod time.Duration // expected resync period value
expectedLabelSelector string // expected label selector value
expectedPodMode string
- expectedFallthrough bool
+ expectedFallthrough *[]string
expectedUpstreams []string
}{
// positive
@@ -32,7 +32,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -44,7 +44,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -57,7 +57,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -71,7 +71,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -85,7 +85,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -99,7 +99,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -113,7 +113,7 @@ func TestKubernetesParse(t *testing.T) {
30 * time.Second,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -127,7 +127,7 @@ func TestKubernetesParse(t *testing.T) {
15 * time.Minute,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -141,7 +141,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"environment=prod",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -155,7 +155,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"application=nginx,environment in (production,qa,staging)",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -173,7 +173,7 @@ func TestKubernetesParse(t *testing.T) {
15 * time.Minute,
"application=nginx,environment in (production,qa,staging)",
podModeDisabled,
- true,
+ &[]string{},
nil,
},
// negative
@@ -188,7 +188,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -202,7 +202,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -216,7 +216,7 @@ func TestKubernetesParse(t *testing.T) {
0 * time.Minute,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -230,7 +230,7 @@ func TestKubernetesParse(t *testing.T) {
0 * time.Second,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -244,7 +244,7 @@ func TestKubernetesParse(t *testing.T) {
0 * time.Second,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -258,7 +258,7 @@ func TestKubernetesParse(t *testing.T) {
0 * time.Second,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
{
@@ -272,7 +272,7 @@ func TestKubernetesParse(t *testing.T) {
0 * time.Second,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
// pods disabled
@@ -287,7 +287,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
// pods insecure
@@ -302,7 +302,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeInsecure,
- false,
+ nil,
nil,
},
// pods verified
@@ -317,7 +317,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeVerified,
- false,
+ nil,
nil,
},
// pods invalid
@@ -332,22 +332,22 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeVerified,
- false,
+ nil,
nil,
},
- // fallthrough invalid
+ // fallthrough with zones
{
`kubernetes coredns.local {
- fallthrough junk
+ fallthrough ip6.arpa inaddr.arpa foo.com
}`,
- true,
+ false,
"rong argument count",
- -1,
+ 1,
0,
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ &[]string{"ip6.arpa", "inaddr.arpa", "foo.com"},
nil,
},
// Valid upstream
@@ -362,7 +362,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
[]string{"13.14.15.16:53"},
},
// Invalid upstream
@@ -377,7 +377,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- false,
+ nil,
nil,
},
}
@@ -444,8 +444,22 @@ func TestKubernetesParse(t *testing.T) {
// 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)
+ if foundFallthrough != nil {
+ failed := false
+ if test.expectedFallthrough == nil {
+ failed = true
+ } else if len(*foundFallthrough) != len(*test.expectedFallthrough) {
+ failed = true
+ } else {
+ for i := range *foundFallthrough {
+ if (*foundFallthrough)[i] != (*test.expectedFallthrough)[i] {
+ failed = true
+ }
+ }
+ }
+ if failed {
+ 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)
+ }
}
// upstream
foundUpstreams := k8sController.Proxy.Upstreams
diff --git a/plugin/plugin.go b/plugin/plugin.go
index a50f10830..137bb48af 100644
--- a/plugin/plugin.go
+++ b/plugin/plugin.go
@@ -83,6 +83,21 @@ func NextOrFailure(name string, next Handler, ctx context.Context, w dns.Respons
return dns.RcodeServerFailure, Error(name, errors.New("no next plugin found"))
}
+// Fallthrough handles the fallthrough logic used in plugins that support it
+func Fallthrough(ftzones *[]string, qname string) bool {
+ if ftzones == nil {
+ return false
+ }
+ if len(*ftzones) == 0 {
+ return true
+ }
+ zone := Zones(*ftzones).Matches(qname)
+ if zone != "" {
+ return true
+ }
+ return false
+}
+
// ClientWrite returns true if the response has been written to the client.
// Each plugin to adhire to this protocol.
func ClientWrite(rcode int) bool {
diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go
index b0736c3a0..80c253843 100644
--- a/plugin/plugin_test.go
+++ b/plugin/plugin_test.go
@@ -1 +1,21 @@
package plugin
+
+import "testing"
+
+func TestFallthrough(t *testing.T) {
+ if Fallthrough(nil, "foo.com.") {
+ t.Errorf("Expected false, got true for nil fallthrough")
+ }
+
+ if !Fallthrough(&[]string{}, "foo.net.") {
+ t.Errorf("Expected true, got false for all zone fallthrough")
+ }
+
+ if Fallthrough(&[]string{"foo.com", "bar.com"}, "foo.net") {
+ t.Errorf("Expected false, got true for non-matching fallthrough zone")
+ }
+
+ if !Fallthrough(&[]string{"foo.com.", "bar.com."}, "bar.com.") {
+ t.Errorf("Expected true, got false for matching fallthrough zone")
+ }
+}