Support SkyDNS' stubzones

This implements stubzones in the same way as SkyDNS. This
also works with multiple configured domains and has tests.
Also add more configuration parameters for TLS and path prefix and
enabling stubzones.  Run StubUpdates as a startup command to keep up to
date with the list in etcd.
This commit is contained in:
Miek Gieben
2016-03-25 20:26:42 +00:00
parent a832ab696a
commit ebef64280a
8 changed files with 403 additions and 98 deletions

View File

@@ -21,10 +21,16 @@ const defaultEndpoint = "http://127.0.0.1:2379"
// Etcd sets up the etcd middleware.
func Etcd(c *Controller) (middleware.Middleware, error) {
etcd, err := etcdParse(c)
etcd, stubzones, err := etcdParse(c)
if err != nil {
return nil, err
}
if stubzones {
c.Startup = append(c.Startup, func() error {
etcd.UpdateStubZones()
return nil
})
}
return func(next middleware.Handler) middleware.Handler {
etcd.Next = next
@@ -32,31 +38,113 @@ func Etcd(c *Controller) (middleware.Middleware, error) {
}, nil
}
func etcdParse(c *Controller) (etcd.Etcd, error) {
func etcdParse(c *Controller) (etcd.Etcd, bool, error) {
stub := make(map[string]proxy.Proxy)
etc := etcd.Etcd{
// make stuff configurable
Proxy: proxy.New([]string{"8.8.8.8:53"}),
PathPrefix: "skydns",
Ctx: context.Background(),
Inflight: &singleflight.Group{},
Stubmap: &stub,
}
var (
client etcdc.KeysAPI
tlsCertFile = ""
tlsKeyFile = ""
tlsCAcertFile = ""
endpoints = []string{defaultEndpoint}
stubzones = false
)
for c.Next() {
if c.Val() == "etcd" {
// etcd [origin...]
client, err := newEtcdClient([]string{defaultEndpoint}, "", "", "")
if err != nil {
return etcd.Etcd{}, err
}
etc.Client = client
etc.Zones = c.RemainingArgs()
if len(etc.Zones) == 0 {
etc.Zones = c.ServerBlockHosts
}
middleware.Zones(etc.Zones).FullyQualify()
return etc, nil
if c.NextBlock() {
// TODO(miek): 2 switches?
switch c.Val() {
case "stubzones":
stubzones = true
case "path":
if !c.NextArg() {
return etcd.Etcd{}, false, c.ArgErr()
}
etc.PathPrefix = c.Val()
case "endpoint":
args := c.RemainingArgs()
if len(args) == 0 {
return etcd.Etcd{}, false, c.ArgErr()
}
endpoints = args
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return etcd.Etcd{}, false, c.ArgErr()
}
for i := 0; i < len(args); i++ {
h, p, e := net.SplitHostPort(args[i])
if e != nil && p == "" {
args[i] = h + ":53"
}
}
endpoints = args
etc.Proxy = proxy.New(args)
case "tls": // cert key cacertfile
args := c.RemainingArgs()
if len(args) != 3 {
return etcd.Etcd{}, false, c.ArgErr()
}
tlsCertFile, tlsKeyFile, tlsCAcertFile = args[0], args[1], args[2]
}
for c.Next() {
switch c.Val() {
case "stubzones":
stubzones = true
case "path":
if !c.NextArg() {
return etcd.Etcd{}, false, c.ArgErr()
}
etc.PathPrefix = c.Val()
case "endpoint":
args := c.RemainingArgs()
if len(args) == 0 {
return etcd.Etcd{}, false, c.ArgErr()
}
endpoints = args
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
return etcd.Etcd{}, false, c.ArgErr()
}
for i := 0; i < len(args); i++ {
h, p, e := net.SplitHostPort(args[i])
if e != nil && p == "" {
args[i] = h + ":53"
}
}
endpoints = args
etc.Proxy = proxy.New(args)
case "tls": // cert key cacertfile
args := c.RemainingArgs()
if len(args) != 3 {
return etcd.Etcd{}, false, c.ArgErr()
}
tlsCertFile, tlsKeyFile, tlsCAcertFile = args[0], args[1], args[2]
}
}
}
client, err := newEtcdClient(endpoints, tlsCertFile, tlsKeyFile, tlsCAcertFile)
if err != nil {
return etcd.Etcd{}, false, err
}
etc.Client = client
return etc, stubzones, nil
}
}
return etcd.Etcd{}, nil
return etcd.Etcd{}, false, nil
}
func newEtcdClient(endpoints []string, tlsCert, tlsKey, tlsCACert string) (etcdc.KeysAPI, error) {