coredns/plugin/kubernetes/setup.go
Miek Gieben 928de738dd
Rename reverse zone constants (#1568)
Rename the constants to IP4arpa and IP6arpa (shorter and exported) and
make IsReverse return the type of the reverse zone which could be handy
for some callers.

Also add tests for IsReverse()
2018-02-28 08:43:19 -08:00

247 lines
5.5 KiB
Go

package kubernetes
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/coredns/coredns/plugin/pkg/parse"
"github.com/coredns/coredns/plugin/pkg/upstream"
"github.com/mholt/caddy"
"github.com/miekg/dns"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func init() {
caddy.RegisterPlugin("kubernetes", caddy.Plugin{
ServerType: "dns",
Action: setup,
})
}
func setup(c *caddy.Controller) error {
k, err := kubernetesParse(c)
if err != nil {
return plugin.Error("kubernetes", err)
}
err = k.InitKubeCache()
if err != nil {
return plugin.Error("kubernetes", err)
}
k.RegisterKubeCache(c)
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
k.Next = next
return k
})
return nil
}
// RegisterKubeCache registers KubeCache start and stop functions with Caddy
func (k *Kubernetes) RegisterKubeCache(c *caddy.Controller) {
c.OnStartup(func() error {
go k.APIConn.Run()
if k.APIProxy != nil {
k.APIProxy.Run()
}
synced := false
for synced == false {
synced = k.APIConn.HasSynced()
time.Sleep(100 * time.Millisecond)
}
return nil
})
c.OnShutdown(func() error {
if k.APIProxy != nil {
k.APIProxy.Stop()
}
return k.APIConn.Stop()
})
}
func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
var k8s *Kubernetes
var err error
for i := 1; c.Next(); i++ {
if i > 1 {
return nil, fmt.Errorf("only one kubernetes section allowed per server block")
}
k8s, err = ParseStanza(c)
if err != nil {
return k8s, err
}
}
return k8s, nil
}
// ParseStanza parses a kubernetes stanza
func ParseStanza(c *caddy.Controller) (*Kubernetes, error) {
k8s := New([]string{""})
k8s.interfaceAddrsFunc = localPodIP
k8s.autoPathSearch = searchFromResolvConf()
opts := dnsControlOpts{
initEndpointsCache: true,
resyncPeriod: defaultResyncPeriod,
}
k8s.opts = opts
zones := c.RemainingArgs()
if len(zones) != 0 {
k8s.Zones = zones
for i := 0; i < len(k8s.Zones); i++ {
k8s.Zones[i] = plugin.Host(k8s.Zones[i]).Normalize()
}
} else {
k8s.Zones = make([]string, len(c.ServerBlockKeys))
for i := 0; i < len(c.ServerBlockKeys); i++ {
k8s.Zones[i] = plugin.Host(c.ServerBlockKeys[i]).Normalize()
}
}
k8s.primaryZoneIndex = -1
for i, z := range k8s.Zones {
if dnsutil.IsReverse(z) > 0 {
continue
}
k8s.primaryZoneIndex = i
break
}
if k8s.primaryZoneIndex == -1 {
return nil, errors.New("non-reverse zone name must be used")
}
for c.NextBlock() {
switch c.Val() {
case "endpoint_pod_names":
args := c.RemainingArgs()
if len(args) > 0 {
return nil, c.ArgErr()
}
k8s.endpointNameMode = true
continue
case "pods":
args := c.RemainingArgs()
if len(args) == 1 {
switch args[0] {
case podModeDisabled, podModeInsecure, podModeVerified:
k8s.podMode = args[0]
default:
return nil, fmt.Errorf("wrong value for pods: %s, must be one of: disabled, verified, insecure", args[0])
}
continue
}
return nil, c.ArgErr()
case "namespaces":
args := c.RemainingArgs()
if len(args) > 0 {
for _, a := range args {
k8s.Namespaces[a] = true
}
continue
}
return nil, c.ArgErr()
case "endpoint":
args := c.RemainingArgs()
if len(args) > 0 {
k8s.APIServerList = args
continue
}
return nil, c.ArgErr()
case "tls": // cert key cacertfile
args := c.RemainingArgs()
if len(args) == 3 {
k8s.APIClientCert, k8s.APIClientKey, k8s.APICertAuth = args[0], args[1], args[2]
continue
}
return nil, c.ArgErr()
case "resyncperiod":
args := c.RemainingArgs()
if len(args) > 0 {
rp, err := time.ParseDuration(args[0])
if err != nil {
return nil, fmt.Errorf("unable to parse resync duration value: '%v': %v", args[0], err)
}
k8s.opts.resyncPeriod = rp
continue
}
return nil, c.ArgErr()
case "labels":
args := c.RemainingArgs()
if len(args) > 0 {
labelSelectorString := strings.Join(args, " ")
ls, err := meta.ParseToLabelSelector(labelSelectorString)
if err != nil {
return nil, fmt.Errorf("unable to parse label selector value: '%v': %v", labelSelectorString, err)
}
k8s.opts.labelSelector = ls
continue
}
return nil, c.ArgErr()
case "fallthrough":
k8s.Fall.SetZonesFromArgs(c.RemainingArgs())
case "upstream":
args := c.RemainingArgs()
u, err := upstream.NewUpstream(args)
if err != nil {
return nil, err
}
k8s.Upstream = u
case "ttl":
args := c.RemainingArgs()
if len(args) == 0 {
return nil, c.ArgErr()
}
t, err := strconv.Atoi(args[0])
if err != nil {
return nil, err
}
if t < 5 || t > 3600 {
return nil, c.Errf("ttl must be in range [5, 3600]: %d", t)
}
k8s.ttl = uint32(t)
case "transfer":
tos, froms, err := parse.Transfer(c, false)
if err != nil {
return nil, err
}
if len(froms) != 0 {
return nil, c.Errf("transfer from is not supported with this plugin")
}
k8s.TransferTo = tos
case "noendpoints":
if len(c.RemainingArgs()) != 0 {
return nil, c.ArgErr()
}
k8s.opts.initEndpointsCache = false
default:
return nil, c.Errf("unknown property '%s'", c.Val())
}
}
return k8s, nil
}
func searchFromResolvConf() []string {
rc, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
return nil
}
plugin.Zones(rc.Search).Normalize()
return rc.Search
}
const defaultResyncPeriod = 5 * time.Minute