diff options
-rw-r--r-- | middleware/kubernetes/controller.go | 54 | ||||
-rw-r--r-- | middleware/kubernetes/kubernetes.go | 42 | ||||
-rw-r--r-- | middleware/kubernetes/kubernetes_test.go | 25 | ||||
-rw-r--r-- | middleware/kubernetes/nametemplate/nametemplate.go | 4 | ||||
-rw-r--r-- | middleware/kubernetes/util/util.go | 42 | ||||
-rw-r--r-- | middleware/kubernetes/util/util_test.go | 55 | ||||
-rw-r--r-- | middleware/pkg/strings/slice.go | 11 |
7 files changed, 86 insertions, 147 deletions
diff --git a/middleware/kubernetes/controller.go b/middleware/kubernetes/controller.go index 126d415ae..943e4e32a 100644 --- a/middleware/kubernetes/controller.go +++ b/middleware/kubernetes/controller.go @@ -5,8 +5,6 @@ import ( "sync" "time" - "github.com/miekg/coredns/middleware/kubernetes/util" - "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/client/cache" client "k8s.io/kubernetes/pkg/client/unversioned" @@ -19,6 +17,19 @@ var ( namespace = api.NamespaceAll ) +// storeToNamespaceLister makes a Store that lists Namespaces. +type storeToNamespaceLister struct { + cache.Store +} + +// List lists all Namespaces in the store. +func (s *storeToNamespaceLister) List() (ns api.NamespaceList, err error) { + for _, m := range s.Store.List() { + ns.Items = append(ns.Items, *(m.(*api.Namespace))) + } + return ns, nil +} + type dnsController struct { client *client.Client @@ -30,7 +41,7 @@ type dnsController struct { svcLister cache.StoreToServiceLister endpLister cache.StoreToEndpointsLister - nsLister util.StoreToNamespaceLister + nsLister storeToNamespaceLister // stopLock is used to enforce only a single call to Stop is active. // Needed because we allow stopping through an http endpoint and @@ -55,12 +66,15 @@ func newdnsController(kubeClient *client.Client, resyncPeriod time.Duration, lse }, &api.Endpoints{}, resyncPeriod, cache.ResourceEventHandlerFuncs{}) - dns.svcLister.Store, dns.svcController = cache.NewInformer( + dns.svcLister.Indexer, dns.svcController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: serviceListFunc(dns.client, namespace, dns.selector), WatchFunc: serviceWatchFunc(dns.client, namespace, dns.selector), }, - &api.Service{}, resyncPeriod, cache.ResourceEventHandlerFuncs{}) + &api.Service{}, + resyncPeriod, + cache.ResourceEventHandlerFuncs{}, + cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) dns.nsLister.Store, dns.nsController = cache.NewInformer( &cache.ListWatch{ @@ -163,27 +177,23 @@ func (dns *dnsController) GetNamespaceList() *api.NamespaceList { return &nsList } -func (dns *dnsController) GetServiceList() *api.ServiceList { - svcList, err := dns.svcLister.List() +func (dns *dnsController) GetServiceList() []*api.Service { + svcs, err := dns.svcLister.List(labels.Everything()) if err != nil { - return &api.ServiceList{} + return []*api.Service{} } - return &svcList + return svcs } // GetServicesByNamespace returns a map of // namespacename :: [ kubernetesService ] func (dns *dnsController) GetServicesByNamespace() map[string][]api.Service { k8sServiceList := dns.GetServiceList() - if k8sServiceList == nil { - return nil - } - - items := make(map[string][]api.Service, len(k8sServiceList.Items)) - for _, i := range k8sServiceList.Items { + items := make(map[string][]api.Service, len(k8sServiceList)) + for _, i := range k8sServiceList { namespace := i.Namespace - items[namespace] = append(items[namespace], i) + items[namespace] = append(items[namespace], *i) } return items @@ -192,18 +202,10 @@ func (dns *dnsController) GetServicesByNamespace() map[string][]api.Service { // GetServiceInNamespace returns the Service that matches // servicename in the namespace func (dns *dnsController) GetServiceInNamespace(namespace string, servicename string) *api.Service { - svcKey := fmt.Sprintf("%v/%v", namespace, servicename) - svcObj, svcExists, err := dns.svcLister.Store.GetByKey(svcKey) - + svcObj, err := dns.svcLister.Services(namespace).Get(servicename) if err != nil { // TODO(...): should return err here return nil } - - if !svcExists { - // TODO(...): should return err here - return nil - } - - return svcObj.(*api.Service) + return svcObj } diff --git a/middleware/kubernetes/kubernetes.go b/middleware/kubernetes/kubernetes.go index 7f5a86649..ae57c6e98 100644 --- a/middleware/kubernetes/kubernetes.go +++ b/middleware/kubernetes/kubernetes.go @@ -4,13 +4,14 @@ package kubernetes import ( "errors" "log" + "strings" "time" "github.com/miekg/coredns/middleware" "github.com/miekg/coredns/middleware/etcd/msg" "github.com/miekg/coredns/middleware/kubernetes/nametemplate" - "github.com/miekg/coredns/middleware/kubernetes/util" "github.com/miekg/coredns/middleware/pkg/dnsutil" + dns_strings "github.com/miekg/coredns/middleware/pkg/strings" "github.com/miekg/coredns/middleware/proxy" "github.com/miekg/dns" @@ -126,21 +127,21 @@ func (k *Kubernetes) Records(name string, exact bool) ([]msg.Service, error) { if namespace == "" { err := errors.New("Parsing query string did not produce a namespace value. Assuming wildcard namespace.") log.Printf("[WARN] %v\n", err) - namespace = util.WildcardStar + namespace = "*" } if serviceName == "" { err := errors.New("Parsing query string did not produce a serviceName value. Assuming wildcard serviceName.") log.Printf("[WARN] %v\n", err) - serviceName = util.WildcardStar + serviceName = "*" } - nsWildcard := util.SymbolContainsWildcard(namespace) - serviceWildcard := util.SymbolContainsWildcard(serviceName) + nsWildcard := symbolContainsWildcard(namespace) + serviceWildcard := symbolContainsWildcard(serviceName) // Abort if the namespace does not contain a wildcard, and namespace is not published per CoreFile // Case where namespace contains a wildcard is handled in Get(...) method. - if (!nsWildcard) && (len(k.Namespaces) > 0) && (!util.StringInSlice(namespace, k.Namespaces)) { + if (!nsWildcard) && (len(k.Namespaces) > 0) && (!dns_strings.StringInSlice(namespace, k.Namespaces)) { return nil, nil } @@ -158,7 +159,7 @@ func (k *Kubernetes) Records(name string, exact bool) ([]msg.Service, error) { } // TODO: assemble name from parts found in k8s data based on name template rather than reusing query string -func (k *Kubernetes) getRecordsForServiceItems(serviceItems []api.Service, values nametemplate.NameValues) []msg.Service { +func (k *Kubernetes) getRecordsForServiceItems(serviceItems []*api.Service, values nametemplate.NameValues) []msg.Service { var records []msg.Service for _, item := range serviceItems { @@ -181,16 +182,16 @@ func (k *Kubernetes) getRecordsForServiceItems(serviceItems []api.Service, value } // Get performs the call to the Kubernetes http API. -func (k *Kubernetes) Get(namespace string, nsWildcard bool, servicename string, serviceWildcard bool) ([]api.Service, error) { +func (k *Kubernetes) Get(namespace string, nsWildcard bool, servicename string, serviceWildcard bool) ([]*api.Service, error) { serviceList := k.APIConn.GetServiceList() - var resultItems []api.Service + var resultItems []*api.Service - for _, item := range serviceList.Items { + for _, item := range serviceList { if symbolMatches(namespace, item.Namespace, nsWildcard) && symbolMatches(servicename, item.Name, serviceWildcard) { // If namespace has a wildcard, filter results against Corefile namespace list. // (Namespaces without a wildcard were filtered before the call to this function.) - if nsWildcard && (len(k.Namespaces) > 0) && (!util.StringInSlice(item.Namespace, k.Namespaces)) { + if nsWildcard && (len(k.Namespaces) > 0) && (!dns_strings.StringInSlice(item.Namespace, k.Namespaces)) { continue } resultItems = append(resultItems, item) @@ -205,9 +206,9 @@ func symbolMatches(queryString string, candidateString string, wildcard bool) bo switch { case !wildcard: result = (queryString == candidateString) - case queryString == util.WildcardStar: + case queryString == "*": result = true - case queryString == util.WildcardAny: + case queryString == "any": result = true } return result @@ -219,11 +220,11 @@ func isKubernetesNameError(err error) bool { } func (k *Kubernetes) getServiceRecordForIP(ip, name string) []msg.Service { - svcList, err := k.APIConn.svcLister.List() + svcList, err := k.APIConn.svcLister.List(labels.Everything()) if err != nil { return nil } - for _, service := range svcList.Items { + for _, service := range svcList { if service.Spec.ClusterIP == ip { return []msg.Service{msg.Service{Host: ip}} } @@ -232,10 +233,7 @@ func (k *Kubernetes) getServiceRecordForIP(ip, name string) []msg.Service { return nil } -const ( - priority = 10 // default priority when nothing is set - ttl = 300 // default ttl when nothing is set - minTTL = 60 - hostmaster = "hostmaster" - k8sTimeout = 5 * time.Second -) +// symbolContainsWildcard checks whether symbol contains a wildcard value +func symbolContainsWildcard(symbol string) bool { + return (strings.Contains(symbol, "*") || (symbol == "any")) +} diff --git a/middleware/kubernetes/kubernetes_test.go b/middleware/kubernetes/kubernetes_test.go new file mode 100644 index 000000000..53404ecf5 --- /dev/null +++ b/middleware/kubernetes/kubernetes_test.go @@ -0,0 +1,25 @@ +package kubernetes + +import "testing" + +// Test data for TestSymbolContainsWildcard cases. +var testdataSymbolContainsWildcard = []struct { + Symbol string + ExpectedResult bool +}{ + {"mynamespace", false}, + {"*", true}, + {"any", true}, + {"my*space", true}, + {"*space", true}, + {"myname*", true}, +} + +func TestSymbolContainsWildcard(t *testing.T) { + for _, example := range testdataSymbolContainsWildcard { + actualResult := symbolContainsWildcard(example.Symbol) + if actualResult != example.ExpectedResult { + t.Errorf("Expected SymbolContainsWildcard result '%v' for example string='%v'. Instead got result '%v'.", example.ExpectedResult, example.Symbol, actualResult) + } + } +} diff --git a/middleware/kubernetes/nametemplate/nametemplate.go b/middleware/kubernetes/nametemplate/nametemplate.go index b9c2f20e4..930d4855e 100644 --- a/middleware/kubernetes/nametemplate/nametemplate.go +++ b/middleware/kubernetes/nametemplate/nametemplate.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/miekg/coredns/middleware/kubernetes/util" + dns_strings "github.com/miekg/coredns/middleware/pkg/strings" ) // Likely symbols that require support: @@ -125,7 +125,7 @@ func (t *NameTemplate) GetTypeFromSegmentArray(segments []string) string { typeSegment := t.GetSymbolFromSegmentArray("type", segments) // Limit type to known types symbols - if util.StringInSlice(typeSegment, types) { + if dns_strings.StringInSlice(typeSegment, types) { return "" } diff --git a/middleware/kubernetes/util/util.go b/middleware/kubernetes/util/util.go deleted file mode 100644 index 89cc2b592..000000000 --- a/middleware/kubernetes/util/util.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package kubernetes/util provides helper functions for the kubernetes middleware -package util - -import ( - "strings" - - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/client/cache" -) - -// StringInSlice check whether string a is a member of slice. -func StringInSlice(a string, slice []string) bool { - for _, b := range slice { - if b == a { - return true - } - } - return false -} - -// SymbolContainsWildcard checks whether symbol contains a wildcard value -func SymbolContainsWildcard(symbol string) bool { - return (strings.Contains(symbol, WildcardStar) || (symbol == WildcardAny)) -} - -const ( - WildcardStar = "*" - WildcardAny = "any" -) - -// StoreToNamespaceLister makes a Store that lists Namespaces. -type StoreToNamespaceLister struct { - cache.Store -} - -// List lists all Namespaces in the store. -func (s *StoreToNamespaceLister) List() (ns api.NamespaceList, err error) { - for _, m := range s.Store.List() { - ns.Items = append(ns.Items, *(m.(*api.Namespace))) - } - return ns, nil -} diff --git a/middleware/kubernetes/util/util_test.go b/middleware/kubernetes/util/util_test.go deleted file mode 100644 index 4af64ea50..000000000 --- a/middleware/kubernetes/util/util_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package util - -import ( - "testing" -) - -type InSliceData struct { - Slice []string - String string - InSlice bool -} - -// Test data for TestStringInSlice cases. -var testdataInSlice = []struct { - Slice []string - String string - ExpectedResult bool -}{ - {[]string{"a", "b", "c"}, "a", true}, - {[]string{"a", "b", "c"}, "d", false}, - {[]string{"a", "b", "c"}, "", false}, - {[]string{}, "a", false}, - {[]string{}, "", false}, -} - -func TestStringInSlice(t *testing.T) { - for _, example := range testdataInSlice { - actualResult := StringInSlice(example.String, example.Slice) - if actualResult != example.ExpectedResult { - t.Errorf("Expected stringInSlice result '%v' for example string='%v', slice='%v'. Instead got result '%v'.", example.ExpectedResult, example.String, example.Slice, actualResult) - } - } -} - -// Test data for TestSymbolContainsWildcard cases. -var testdataSymbolContainsWildcard = []struct { - Symbol string - ExpectedResult bool -}{ - {"mynamespace", false}, - {"*", true}, - {"any", true}, - {"my*space", true}, - {"*space", true}, - {"myname*", true}, -} - -func TestSymbolContainsWildcard(t *testing.T) { - for _, example := range testdataSymbolContainsWildcard { - actualResult := SymbolContainsWildcard(example.Symbol) - if actualResult != example.ExpectedResult { - t.Errorf("Expected SymbolContainsWildcard result '%v' for example string='%v'. Instead got result '%v'.", example.ExpectedResult, example.Symbol, actualResult) - } - } -} diff --git a/middleware/pkg/strings/slice.go b/middleware/pkg/strings/slice.go new file mode 100644 index 000000000..3d4b1d481 --- /dev/null +++ b/middleware/pkg/strings/slice.go @@ -0,0 +1,11 @@ +package strings + +// StringInSlice check whether string a is a member of slice. +func StringInSlice(a string, slice []string) bool { + for _, b := range slice { + if b == a { + return true + } + } + return false +} |