plugin/k8s_extenral: Supports fallthrough option (#5959)
* Add fallthrough option to k8s_external plugin to allow transitioning control to the next plugin if the domain is not found * Exit on start up if required plugin is not present. Signed-off-by: vanceli <vanceli@tencent.com> --------- Signed-off-by: vanceli <vanceli@tencent.com> Co-authored-by: vanceli <vanceli@tencent.com>
This commit is contained in:
parent
48c40ae1cd
commit
47dceabfc6
4 changed files with 66 additions and 22 deletions
|
@ -10,8 +10,7 @@ This plugin allows an additional zone to resolve the external IP address(es) of
|
|||
service and headless services. This plugin is only useful if the *kubernetes* plugin is also loaded.
|
||||
|
||||
The plugin uses an external zone to resolve in-cluster IP addresses. It only handles queries for A,
|
||||
AAAA, SRV, and PTR records; all others result in NODATA responses. To make it a proper DNS zone, it handles
|
||||
SOA and NS queries for the apex of the zone.
|
||||
AAAA, SRV, and PTR records; To make it a proper DNS zone, it handles SOA and NS queries for the apex of the zone.
|
||||
|
||||
By default the apex of the zone will look like the following (assuming the zone used is `example.org`):
|
||||
|
||||
|
@ -67,6 +66,14 @@ k8s_external [ZONE...] {
|
|||
|
||||
* if there is a headless service with external IPs set, external IPs will be resolved
|
||||
|
||||
If the queried domain does not exist, you can fall through to next plugin by adding the `fallthrough` option.
|
||||
|
||||
~~~
|
||||
k8s_external [ZONE...] {
|
||||
fallthrough [ZONE...]
|
||||
}
|
||||
~~~
|
||||
|
||||
## Examples
|
||||
|
||||
Enable names under `example.org` to be resolved to in-cluster DNS addresses.
|
||||
|
@ -106,6 +113,18 @@ zone transfers. Notifies are not supported.
|
|||
}
|
||||
~~~
|
||||
|
||||
With the `fallthrough` option, if the queried domain does not exist, it will be passed to the next plugin that matches the zone.
|
||||
|
||||
~~~
|
||||
. {
|
||||
kubernetes cluster.local
|
||||
k8s_external example.org {
|
||||
fallthrough
|
||||
}
|
||||
forward . 8.8.8.8
|
||||
}
|
||||
~~~
|
||||
|
||||
# See Also
|
||||
|
||||
For some background see [resolve external IP address](https://github.com/kubernetes/dns/issues/242).
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/etcd/msg"
|
||||
"github.com/coredns/coredns/plugin/pkg/fall"
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
|
@ -39,6 +40,7 @@ type Externaler interface {
|
|||
type External struct {
|
||||
Next plugin.Handler
|
||||
Zones []string
|
||||
Fall fall.F
|
||||
|
||||
hostmaster string
|
||||
apex string
|
||||
|
@ -68,10 +70,6 @@ func (e *External) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
|
|||
return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
if e.externalFunc == nil {
|
||||
return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
state.Zone = zone
|
||||
for _, z := range e.Zones {
|
||||
// TODO(miek): save this in the External struct.
|
||||
|
@ -93,6 +91,10 @@ func (e *External) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Ms
|
|||
m.Authoritative = true
|
||||
|
||||
if len(svc) == 0 {
|
||||
if e.Fall.Through(state.Name()) && rcode == dns.RcodeNameError {
|
||||
return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
m.Rcode = rcode
|
||||
m.Ns = []dns.RR{e.soa(state)}
|
||||
w.WriteMsg(m)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package external
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
|
@ -9,7 +10,9 @@ import (
|
|||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("k8s_external", setup) }
|
||||
const pluginName = "k8s_external"
|
||||
|
||||
func init() { plugin.Register(pluginName, setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
e, err := parse(c)
|
||||
|
@ -21,14 +24,18 @@ func setup(c *caddy.Controller) error {
|
|||
c.OnStartup(func() error {
|
||||
m := dnsserver.GetConfig(c).Handler("kubernetes")
|
||||
if m == nil {
|
||||
return nil
|
||||
return plugin.Error(pluginName, errors.New("kubernetes plugin not loaded"))
|
||||
}
|
||||
if x, ok := m.(Externaler); ok {
|
||||
e.externalFunc = x.External
|
||||
e.externalAddrFunc = x.ExternalAddress
|
||||
e.externalServicesFunc = x.ExternalServices
|
||||
e.externalSerialFunc = x.ExternalSerial
|
||||
|
||||
x, ok := m.(Externaler)
|
||||
if !ok {
|
||||
return plugin.Error(pluginName, errors.New("kubernetes plugin does not implement the Externaler interface"))
|
||||
}
|
||||
|
||||
e.externalFunc = x.External
|
||||
e.externalAddrFunc = x.ExternalAddress
|
||||
e.externalServicesFunc = x.ExternalServices
|
||||
e.externalSerialFunc = x.ExternalSerial
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -70,6 +77,8 @@ func parse(c *caddy.Controller) (*External, error) {
|
|||
e.apex = args[0]
|
||||
case "headless":
|
||||
e.headless = true
|
||||
case "fallthrough":
|
||||
e.Fall.SetZonesFromArgs(c.RemainingArgs())
|
||||
default:
|
||||
return nil, c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
|
|
|
@ -4,24 +4,33 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/coredns/plugin/pkg/fall"
|
||||
)
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedZone string
|
||||
expectedApex string
|
||||
expectedHeadless bool
|
||||
input string
|
||||
shouldErr bool
|
||||
expectedZone string
|
||||
expectedApex string
|
||||
expectedHeadless bool
|
||||
expectedFallthrough fall.F
|
||||
}{
|
||||
{`k8s_external`, false, "", "dns", false},
|
||||
{`k8s_external example.org`, false, "example.org.", "dns", false},
|
||||
{`k8s_external`, false, "", "dns", false, fall.Zero},
|
||||
{`k8s_external example.org`, false, "example.org.", "dns", false, fall.Zero},
|
||||
{`k8s_external example.org {
|
||||
apex testdns
|
||||
}`, false, "example.org.", "testdns", false},
|
||||
}`, false, "example.org.", "testdns", false, fall.Zero},
|
||||
{`k8s_external example.org {
|
||||
headless
|
||||
}`, false, "example.org.", "dns", true},
|
||||
}`, false, "example.org.", "dns", true, fall.Zero},
|
||||
{`k8s_external example.org {
|
||||
fallthrough
|
||||
}`, false, "example.org.", "dns", false, fall.Root},
|
||||
{`k8s_external example.org {
|
||||
fallthrough ip6.arpa inaddr.arpa foo.com
|
||||
}`, false, "example.org.", "dns", false,
|
||||
fall.F{Zones: []string{"ip6.arpa.", "inaddr.arpa.", "foo.com."}}},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
@ -53,5 +62,10 @@ func TestSetup(t *testing.T) {
|
|||
t.Errorf("Test %d, expected headless %q for input %s, got: %v", i, test.expectedApex, test.input, e.headless)
|
||||
}
|
||||
}
|
||||
if !test.shouldErr {
|
||||
if !e.Fall.Equal(test.expectedFallthrough) {
|
||||
t.Errorf("Test %d, expected to be initialized with fallthrough %q for input %s, got: %v", i, test.expectedFallthrough, test.input, e.Fall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue