mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-26 22:01:04 +01:00 
			
		
		
		
	Make normalize return multiple "hosts" (= reverse zones) when a non-octet boundary cidr is given. Added pkg/cidr package that holds the cidr calculation routines; felt they didn't really fit dnsutil. This change means the IPNet return parameter isn't needed, the hosts are all correct. The tests that tests this is also removed: TestSplitHostPortReverse The fallout was that zoneAddr _also_ doesn't need the IPNet member, that in turn make it visible that zoneAddr in address.go duplicated a bunch of stuff from register.go; removed/refactored that too. Created a plugin.OriginsFromArgsOrServerBlock to help plugins do the right things, by consuming ZONE arguments; this now expands reverse zones correctly. This is mostly mechanical. Remove the reverse test in plugin/kubernetes which is a copy-paste from a core test (which has since been fixed). Remove MustNormalize as it has no plugin users. This change is not backwards compatible to plugins that have a ZONE argument that they parse in the setup util. All in-tree plugins have been updated. Signed-off-by: Miek Gieben <miek@miek.nl>
		
			
				
	
	
		
			254 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package kubernetes
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/coredns/caddy"
 | |
| 	"github.com/coredns/coredns/core/dnsserver"
 | |
| 	"github.com/coredns/coredns/plugin"
 | |
| 	"github.com/coredns/coredns/plugin/pkg/dnsutil"
 | |
| 	clog "github.com/coredns/coredns/plugin/pkg/log"
 | |
| 	"github.com/coredns/coredns/plugin/pkg/upstream"
 | |
| 
 | |
| 	"github.com/miekg/dns"
 | |
| 	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"       // pull this in here, because we want it excluded if plugin.cfg doesn't have k8s
 | |
| 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"      // pull this in here, because we want it excluded if plugin.cfg doesn't have k8s
 | |
| 	_ "k8s.io/client-go/plugin/pkg/client/auth/openstack" // pull this in here, because we want it excluded if plugin.cfg doesn't have k8s
 | |
| 	"k8s.io/client-go/tools/clientcmd"
 | |
| 	"k8s.io/klog"
 | |
| )
 | |
| 
 | |
| const pluginName = "kubernetes"
 | |
| 
 | |
| var log = clog.NewWithPlugin(pluginName)
 | |
| 
 | |
| func init() { plugin.Register(pluginName, setup) }
 | |
| 
 | |
| func setup(c *caddy.Controller) error {
 | |
| 	klog.SetOutput(os.Stdout)
 | |
| 
 | |
| 	k, err := kubernetesParse(c)
 | |
| 	if err != nil {
 | |
| 		return plugin.Error(pluginName, err)
 | |
| 	}
 | |
| 
 | |
| 	onStart, onShut, err := k.InitKubeCache(context.Background())
 | |
| 	if err != nil {
 | |
| 		return plugin.Error(pluginName, err)
 | |
| 	}
 | |
| 	if onStart != nil {
 | |
| 		c.OnStartup(onStart)
 | |
| 	}
 | |
| 	if onShut != nil {
 | |
| 		c.OnShutdown(onShut)
 | |
| 	}
 | |
| 
 | |
| 	dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
 | |
| 		k.Next = next
 | |
| 		return k
 | |
| 	})
 | |
| 
 | |
| 	// get locally bound addresses
 | |
| 	c.OnStartup(func() error {
 | |
| 		k.localIPs = boundIPs(c)
 | |
| 		return nil
 | |
| 	})
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
 | |
| 	var (
 | |
| 		k8s *Kubernetes
 | |
| 		err error
 | |
| 	)
 | |
| 
 | |
| 	i := 0
 | |
| 	for c.Next() {
 | |
| 		if i > 0 {
 | |
| 			return nil, plugin.ErrOnce
 | |
| 		}
 | |
| 		i++
 | |
| 
 | |
| 		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.autoPathSearch = searchFromResolvConf()
 | |
| 
 | |
| 	opts := dnsControlOpts{
 | |
| 		initEndpointsCache: true,
 | |
| 		ignoreEmptyService: false,
 | |
| 	}
 | |
| 	k8s.opts = opts
 | |
| 
 | |
| 	k8s.Zones = plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), c.ServerBlockKeys)
 | |
| 
 | |
| 	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")
 | |
| 	}
 | |
| 
 | |
| 	k8s.Upstream = upstream.New()
 | |
| 
 | |
| 	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] = struct{}{}
 | |
| 				}
 | |
| 				continue
 | |
| 			}
 | |
| 			return nil, c.ArgErr()
 | |
| 		case "endpoint":
 | |
| 			args := c.RemainingArgs()
 | |
| 			if len(args) > 0 {
 | |
| 				// Multiple endpoints are deprecated but still could be specified,
 | |
| 				// only the first one be used, though
 | |
| 				k8s.APIServerList = args
 | |
| 				if len(args) > 1 {
 | |
| 					log.Warningf("Multiple endpoints have been deprecated, only the first specified endpoint '%s' is used", args[0])
 | |
| 				}
 | |
| 				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 "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 "namespace_labels":
 | |
| 			args := c.RemainingArgs()
 | |
| 			if len(args) > 0 {
 | |
| 				namespaceLabelSelectorString := strings.Join(args, " ")
 | |
| 				nls, err := meta.ParseToLabelSelector(namespaceLabelSelectorString)
 | |
| 				if err != nil {
 | |
| 					return nil, fmt.Errorf("unable to parse namespace_label selector value: '%v': %v", namespaceLabelSelectorString, err)
 | |
| 				}
 | |
| 				k8s.opts.namespaceLabelSelector = nls
 | |
| 				continue
 | |
| 			}
 | |
| 			return nil, c.ArgErr()
 | |
| 		case "fallthrough":
 | |
| 			k8s.Fall.SetZonesFromArgs(c.RemainingArgs())
 | |
| 		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 < 0 || t > 3600 {
 | |
| 				return nil, c.Errf("ttl must be in range [0, 3600]: %d", t)
 | |
| 			}
 | |
| 			k8s.ttl = uint32(t)
 | |
| 		case "noendpoints":
 | |
| 			if len(c.RemainingArgs()) != 0 {
 | |
| 				return nil, c.ArgErr()
 | |
| 			}
 | |
| 			k8s.opts.initEndpointsCache = false
 | |
| 		case "ignore":
 | |
| 			args := c.RemainingArgs()
 | |
| 			if len(args) > 0 {
 | |
| 				ignore := args[0]
 | |
| 				if ignore == "empty_service" {
 | |
| 					k8s.opts.ignoreEmptyService = true
 | |
| 					continue
 | |
| 				} else {
 | |
| 					return nil, fmt.Errorf("unable to parse ignore value: '%v'", ignore)
 | |
| 				}
 | |
| 			}
 | |
| 		case "kubeconfig":
 | |
| 			args := c.RemainingArgs()
 | |
| 			if len(args) != 1 && len(args) != 2 {
 | |
| 				return nil, c.ArgErr()
 | |
| 			}
 | |
| 			overrides := &clientcmd.ConfigOverrides{}
 | |
| 			if len(args) == 2 {
 | |
| 				overrides.CurrentContext = args[1]
 | |
| 			}
 | |
| 			config := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
 | |
| 				&clientcmd.ClientConfigLoadingRules{ExplicitPath: args[0]},
 | |
| 				overrides,
 | |
| 			)
 | |
| 			k8s.ClientConfig = config
 | |
| 		default:
 | |
| 			return nil, c.Errf("unknown property '%s'", c.Val())
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(k8s.Namespaces) != 0 && k8s.opts.namespaceLabelSelector != nil {
 | |
| 		return nil, c.Errf("namespaces and namespace_labels cannot both be set")
 | |
| 	}
 | |
| 
 | |
| 	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
 | |
| }
 |