mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	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>
This commit is contained in:
		
							
								
								
									
										112
									
								
								plugin/k8s_external/external.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								plugin/k8s_external/external.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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" } | ||||
		Reference in New Issue
	
	Block a user