aboutsummaryrefslogtreecommitdiff
path: root/plugin/k8s_external/external.go
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2018-12-14 09:41:51 +0000
committerGravatar GitHub <noreply@github.com> 2018-12-14 09:41:51 +0000
commitc1c98924c3733b853115c62adc1a2b5978ae2df3 (patch)
tree6006978128c2ffd02eb9c5eaaeb16993f38f205b /plugin/k8s_external/external.go
parentd9880681c3b28f8506e2a5b15bbc404b2a155b00 (diff)
downloadcoredns-c1c98924c3733b853115c62adc1a2b5978ae2df3.tar.gz
coredns-c1c98924c3733b853115c62adc1a2b5978ae2df3.tar.zst
coredns-c1c98924c3733b853115c62adc1a2b5978ae2df3.zip
Add new plugin: external - resolve k8s ingress and LB address with external names (#2379)
* Add new plugin: external This plugin works in conjunction with the kubernetes plugin and exports ingress and LB addresses as DNS records. It bypasses backend.go and backend_lookup.go flow because it is not needed. README, tests are implemented. The tests only exercise the unit tests, this has not been tested in any ci. Signed-off-by: Miek Gieben <miek@miek.nl> * Rename to k8s_external Signed-off-by: Miek Gieben <miek@miek.nl> * go gen Signed-off-by: Miek Gieben <miek@miek.nl>
Diffstat (limited to 'plugin/k8s_external/external.go')
-rw-r--r--plugin/k8s_external/external.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/plugin/k8s_external/external.go b/plugin/k8s_external/external.go
new file mode 100644
index 000000000..3ca188ed8
--- /dev/null
+++ b/plugin/k8s_external/external.go
@@ -0,0 +1,112 @@
+/*
+Package external implements external names for kubernetes clusters.
+
+This plugin only handles three qtypes (except the apex queries, because those are handled
+differently). We support A, AAAA and SRV request, for all other types we return NODATA or
+NXDOMAIN depending on the state of the cluster.
+
+A plugin willing to provide these services must implement the Externaler interface, although it
+likely only makes sense for the *kubernetes* plugin.
+
+*/
+package external
+
+import (
+ "context"
+
+ "github.com/coredns/coredns/plugin"
+ "github.com/coredns/coredns/plugin/etcd/msg"
+ "github.com/coredns/coredns/request"
+
+ "github.com/miekg/dns"
+)
+
+// Externaler defines the interface that a plugin should implement in order to be used by External.
+type Externaler interface {
+ // External returns a slice of msg.Services that are looked up in the backend and match
+ // the request.
+ External(request.Request) ([]msg.Service, int)
+ // ExternalAddress should return a string slice of addresses for the nameserving endpoint.
+ ExternalAddress(state request.Request) []dns.RR
+}
+
+// External resolves Ingress and Loadbalance IPs from kubernetes clusters.
+type External struct {
+ Next plugin.Handler
+ Zones []string
+
+ hostmaster string
+ apex string
+ ttl uint32
+
+ externalFunc func(request.Request) ([]msg.Service, int)
+ externalAddrFunc func(request.Request) []dns.RR
+}
+
+// New returns a new and initialized *External.
+func New() *External {
+ e := &External{hostmaster: "hostmaster", ttl: 5, apex: "dns"}
+ return e
+}
+
+// ServeDNS implements the plugin.Handle interface.
+func (e *External) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
+ state := request.Request{W: w, Req: r}
+
+ zone := plugin.Zones(e.Zones).Matches(state.Name())
+ if zone == "" {
+ 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.
+ if state.Name() == z { // apex query
+ ret, err := e.serveApex(state)
+ return ret, err
+ }
+ if dns.IsSubDomain(e.apex+"."+z, state.Name()) {
+ // dns subdomain test for ns. and dns. queries
+ ret, err := e.serveSubApex(state)
+ return ret, err
+ }
+ }
+
+ svc, rcode := e.externalFunc(state)
+
+ m := new(dns.Msg)
+ m.SetReply(state.Req)
+
+ if len(svc) == 0 {
+ m.Rcode = rcode
+ m.Ns = []dns.RR{e.soa(state)}
+ w.WriteMsg(m)
+ return 0, nil
+ }
+
+ switch state.QType() {
+ case dns.TypeA:
+ m.Answer = e.a(svc, state)
+ case dns.TypeAAAA:
+ m.Answer = e.aaaa(svc, state)
+ case dns.TypeSRV:
+ m.Answer, m.Extra = e.srv(svc, state)
+ default:
+ m.Ns = []dns.RR{e.soa(state)}
+ }
+
+ // If we did have records, but queried for the wrong qtype return a nodata response.
+ if len(m.Answer) == 0 {
+ m.Ns = []dns.RR{e.soa(state)}
+ }
+
+ w.WriteMsg(m)
+ return 0, nil
+}
+
+// Name implements the Handler interface.
+func (e *External) Name() string { return "k8s_external" }