mirror of
https://github.com/coredns/coredns.git
synced 2025-11-13 07:22:16 -05:00
Remove the word middleware (#1067)
* Rename middleware to plugin first pass; mostly used 'sed', few spots where I manually changed text. This still builds a coredns binary. * fmt error * Rename AddMiddleware to AddPlugin * Readd AddMiddleware to remain backwards compat
This commit is contained in:
188
plugin/etcd/etcd.go
Normal file
188
plugin/etcd/etcd.go
Normal file
@@ -0,0 +1,188 @@
|
||||
// Package etcd provides the etcd backend plugin.
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/etcd/msg"
|
||||
"github.com/coredns/coredns/plugin/pkg/cache"
|
||||
"github.com/coredns/coredns/plugin/pkg/singleflight"
|
||||
"github.com/coredns/coredns/plugin/proxy"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
etcdc "github.com/coreos/etcd/client"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Etcd is a plugin talks to an etcd cluster.
|
||||
type Etcd struct {
|
||||
Next plugin.Handler
|
||||
Fallthrough bool
|
||||
Zones []string
|
||||
PathPrefix string
|
||||
Proxy proxy.Proxy // Proxy for looking up names during the resolution process
|
||||
Client etcdc.KeysAPI
|
||||
Ctx context.Context
|
||||
Inflight *singleflight.Group
|
||||
Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
|
||||
|
||||
endpoints []string // Stored here as well, to aid in testing.
|
||||
}
|
||||
|
||||
// Services implements the ServiceBackend interface.
|
||||
func (e *Etcd) Services(state request.Request, exact bool, opt plugin.Options) (services []msg.Service, err error) {
|
||||
services, err = e.Records(state, exact)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
services = msg.Group(services)
|
||||
return
|
||||
}
|
||||
|
||||
// Reverse implements the ServiceBackend interface.
|
||||
func (e *Etcd) Reverse(state request.Request, exact bool, opt plugin.Options) (services []msg.Service, err error) {
|
||||
return e.Services(state, exact, opt)
|
||||
}
|
||||
|
||||
// Lookup implements the ServiceBackend interface.
|
||||
func (e *Etcd) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
|
||||
return e.Proxy.Lookup(state, name, typ)
|
||||
}
|
||||
|
||||
// IsNameError implements the ServiceBackend interface.
|
||||
func (e *Etcd) IsNameError(err error) bool {
|
||||
if ee, ok := err.(etcdc.Error); ok && ee.Code == etcdc.ErrorCodeKeyNotFound {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Records looks up records in etcd. If exact is true, it will lookup just this
|
||||
// name. This is used when find matches when completing SRV lookups for instance.
|
||||
func (e *Etcd) Records(state request.Request, exact bool) ([]msg.Service, error) {
|
||||
name := state.Name()
|
||||
|
||||
path, star := msg.PathWithWildcard(name, e.PathPrefix)
|
||||
r, err := e.get(path, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
segments := strings.Split(msg.Path(name, e.PathPrefix), "/")
|
||||
switch {
|
||||
case exact && r.Node.Dir:
|
||||
return nil, nil
|
||||
case r.Node.Dir:
|
||||
return e.loopNodes(r.Node.Nodes, segments, star, nil)
|
||||
default:
|
||||
return e.loopNodes([]*etcdc.Node{r.Node}, segments, false, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// get is a wrapper for client.Get that uses SingleInflight to suppress multiple outstanding queries.
|
||||
func (e *Etcd) get(path string, recursive bool) (*etcdc.Response, error) {
|
||||
|
||||
hash := cache.Hash([]byte(path))
|
||||
|
||||
resp, err := e.Inflight.Do(hash, func() (interface{}, error) {
|
||||
ctx, cancel := context.WithTimeout(e.Ctx, etcdTimeout)
|
||||
defer cancel()
|
||||
r, e := e.Client.Get(ctx, path, &etcdc.GetOptions{Sort: false, Recursive: recursive})
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return r, e
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.(*etcdc.Response), err
|
||||
}
|
||||
|
||||
// skydns/local/skydns/east/staging/web
|
||||
// skydns/local/skydns/west/production/web
|
||||
//
|
||||
// skydns/local/skydns/*/*/web
|
||||
// skydns/local/skydns/*/web
|
||||
|
||||
// loopNodes recursively loops through the nodes and returns all the values. The nodes' keyname
|
||||
// will be match against any wildcards when star is true.
|
||||
func (e *Etcd) loopNodes(ns []*etcdc.Node, nameParts []string, star bool, bx map[msg.Service]bool) (sx []msg.Service, err error) {
|
||||
if bx == nil {
|
||||
bx = make(map[msg.Service]bool)
|
||||
}
|
||||
Nodes:
|
||||
for _, n := range ns {
|
||||
if n.Dir {
|
||||
nodes, err := e.loopNodes(n.Nodes, nameParts, star, bx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sx = append(sx, nodes...)
|
||||
continue
|
||||
}
|
||||
if star {
|
||||
keyParts := strings.Split(n.Key, "/")
|
||||
for i, n := range nameParts {
|
||||
if i > len(keyParts)-1 {
|
||||
// name is longer than key
|
||||
continue Nodes
|
||||
}
|
||||
if n == "*" || n == "any" {
|
||||
continue
|
||||
}
|
||||
if keyParts[i] != n {
|
||||
continue Nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
serv := new(msg.Service)
|
||||
if err := json.Unmarshal([]byte(n.Value), serv); err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", n.Key, err.Error())
|
||||
}
|
||||
b := msg.Service{Host: serv.Host, Port: serv.Port, Priority: serv.Priority, Weight: serv.Weight, Text: serv.Text, Key: n.Key}
|
||||
if _, ok := bx[b]; ok {
|
||||
continue
|
||||
}
|
||||
bx[b] = true
|
||||
|
||||
serv.Key = n.Key
|
||||
serv.TTL = e.TTL(n, serv)
|
||||
if serv.Priority == 0 {
|
||||
serv.Priority = priority
|
||||
}
|
||||
sx = append(sx, *serv)
|
||||
}
|
||||
return sx, nil
|
||||
}
|
||||
|
||||
// TTL returns the smaller of the etcd TTL and the service's
|
||||
// TTL. If neither of these are set (have a zero value), a default is used.
|
||||
func (e *Etcd) TTL(node *etcdc.Node, serv *msg.Service) uint32 {
|
||||
etcdTTL := uint32(node.TTL)
|
||||
|
||||
if etcdTTL == 0 && serv.TTL == 0 {
|
||||
return ttl
|
||||
}
|
||||
if etcdTTL == 0 {
|
||||
return serv.TTL
|
||||
}
|
||||
if serv.TTL == 0 {
|
||||
return etcdTTL
|
||||
}
|
||||
if etcdTTL < serv.TTL {
|
||||
return etcdTTL
|
||||
}
|
||||
return serv.TTL
|
||||
}
|
||||
|
||||
const (
|
||||
priority = 10 // default priority when nothing is set
|
||||
ttl = 300 // default ttl when nothing is set
|
||||
etcdTimeout = 5 * time.Second
|
||||
)
|
||||
Reference in New Issue
Block a user