From 974ed086f25ad45a01947e276e2eb8aa73d007a3 Mon Sep 17 00:00:00 2001 From: Chris O'Haver Date: Wed, 10 Oct 2018 15:28:45 -0400 Subject: [PATCH] use keys (#2167) --- plugin/federation/kubernetes_api_test.go | 27 ++-- plugin/kubernetes/controller.go | 90 +++++------- plugin/kubernetes/handler_test.go | 171 +++++++++++------------ plugin/kubernetes/kubernetes.go | 9 +- plugin/kubernetes/kubernetes_test.go | 115 ++++----------- plugin/kubernetes/local.go | 16 ++- plugin/kubernetes/ns.go | 21 ++- plugin/kubernetes/ns_test.go | 54 +++---- plugin/kubernetes/object/endpoint.go | 4 +- plugin/kubernetes/object/service.go | 2 +- plugin/kubernetes/reverse.go | 36 ++--- plugin/kubernetes/reverse_test.go | 68 ++++----- plugin/kubernetes/xfr.go | 58 ++++---- 13 files changed, 291 insertions(+), 380 deletions(-) diff --git a/plugin/federation/kubernetes_api_test.go b/plugin/federation/kubernetes_api_test.go index 4b62605d1..2fa274a6d 100644 --- a/plugin/federation/kubernetes_api_test.go +++ b/plugin/federation/kubernetes_api_test.go @@ -16,22 +16,24 @@ type APIConnFederationTest struct { func (APIConnFederationTest) HasSynced() bool { return true } func (APIConnFederationTest) Run() { return } func (APIConnFederationTest) Stop() error { return nil } -func (APIConnFederationTest) SvcIndexReverse(string) []*object.Service { return nil } -func (APIConnFederationTest) EpIndexReverse(string) []*object.Endpoints { return nil } +func (APIConnFederationTest) SvcIndexReverse(string) *object.Service { return nil } +func (APIConnFederationTest) EpIndexReverse(string) *object.Endpoints { return nil } func (APIConnFederationTest) Modified() int64 { return 0 } func (APIConnFederationTest) SetWatchChan(watch.Chan) {} func (APIConnFederationTest) Watch(string) error { return nil } func (APIConnFederationTest) StopWatching(string) {} + func (APIConnFederationTest) PodIndex(string) []*object.Pod { return []*object.Pod{ {Namespace: "podns", PodIP: "10.240.0.1"}, // Remote IP set in test.ResponseWriter } } -func (APIConnFederationTest) SvcIndex(string) []*object.Service { - svcs := []*object.Service{ - { + +func (APIConnFederationTest) SvcIndex(key string) *object.Service { + svcs := map[string]*object.Service{ + "testns/svc1": { Name: "svc1", Namespace: "testns", ClusterIP: "10.0.0.1", @@ -39,12 +41,12 @@ func (APIConnFederationTest) SvcIndex(string) []*object.Service { {Name: "http", Protocol: "tcp", Port: 80}, }, }, - { + "testns/hdls1": { Name: "hdls1", Namespace: "testns", ClusterIP: api.ClusterIPNone, }, - { + "testns/external": { Name: "external", Namespace: "testns", ExternalName: "ext.interwebs.test", @@ -53,9 +55,10 @@ func (APIConnFederationTest) SvcIndex(string) []*object.Service { }, }, } - return svcs + return svcs[key] } + func (APIConnFederationTest) ServiceList() []*object.Service { svcs := []*object.Service{ { @@ -83,9 +86,9 @@ func (APIConnFederationTest) ServiceList() []*object.Service { return svcs } -func (APIConnFederationTest) EpIndex(string) []*object.Endpoints { - eps := []*object.Endpoints{ - { +func (APIConnFederationTest) EpIndex(key string) *object.Endpoints { + eps := map[string]*object.Endpoints{ + "testns/svc1": { Subsets: []object.EndpointSubset{ { Addresses: []object.EndpointAddress{ @@ -100,7 +103,7 @@ func (APIConnFederationTest) EpIndex(string) []*object.Endpoints { Namespace: "testns", }, } - return eps + return eps[key] } func (APIConnFederationTest) EndpointsList() []*object.Endpoints { diff --git a/plugin/kubernetes/controller.go b/plugin/kubernetes/controller.go index 1c41b6ddf..b1619a624 100644 --- a/plugin/kubernetes/controller.go +++ b/plugin/kubernetes/controller.go @@ -20,21 +20,19 @@ import ( ) const ( - podIPIndex = "PodIP" - svcNameNamespaceIndex = "NameNamespace" - svcIPIndex = "ServiceIP" - epNameNamespaceIndex = "EndpointNameNamespace" - epIPIndex = "EndpointsIP" + podIPIndex = "PodIP" + svcIPIndex = "ServiceIP" + epIPIndex = "EndpointsIP" ) type dnsController interface { ServiceList() []*object.Service EndpointsList() []*object.Endpoints - SvcIndex(string) []*object.Service - SvcIndexReverse(string) []*object.Service + SvcIndex(string) *object.Service + SvcIndexReverse(string) *object.Service PodIndex(string) []*object.Pod - EpIndex(string) []*object.Endpoints - EpIndexReverse(string) []*object.Endpoints + EpIndex(string) *object.Endpoints + EpIndexReverse(string) *object.Endpoints GetNodeByName(string) (*api.Node, error) GetNamespaceByName(string) (*api.Namespace, error) @@ -118,7 +116,7 @@ func newdnsController(kubeClient kubernetes.Interface, opts dnsControlOpts) *dns &object.Service{}, opts.resyncPeriod, cache.ResourceEventHandlerFuncs{AddFunc: dns.Add, UpdateFunc: dns.Update, DeleteFunc: dns.Delete}, - cache.Indexers{svcNameNamespaceIndex: svcNameNamespaceIndexFunc, svcIPIndex: svcIPIndexFunc}, + cache.Indexers{svcIPIndex: svcIPIndexFunc}, object.ToService, ) @@ -145,7 +143,7 @@ func newdnsController(kubeClient kubernetes.Interface, opts dnsControlOpts) *dns &api.Endpoints{}, opts.resyncPeriod, cache.ResourceEventHandlerFuncs{AddFunc: dns.Add, UpdateFunc: dns.Update, DeleteFunc: dns.Delete}, - cache.Indexers{epNameNamespaceIndex: epNameNamespaceIndexFunc, epIPIndex: epIPIndexFunc}, + cache.Indexers{epIPIndex: epIPIndexFunc}, object.ToEndpoints) } @@ -175,22 +173,6 @@ func svcIPIndexFunc(obj interface{}) ([]string, error) { return []string{svc.ClusterIP}, nil } -func svcNameNamespaceIndexFunc(obj interface{}) ([]string, error) { - s, ok := obj.(*object.Service) - if !ok { - return nil, errObj - } - return []string{s.Index}, nil -} - -func epNameNamespaceIndexFunc(obj interface{}) ([]string, error) { - s, ok := obj.(*object.Endpoints) - if !ok { - return nil, errObj - } - return []string{s.Index}, nil -} - func epIPIndexFunc(obj interface{}) ([]string, error) { ep, ok := obj.(*object.Endpoints) if !ok { @@ -359,6 +341,9 @@ func (dns *dnsControl) EndpointsList() (eps []*object.Endpoints) { } func (dns *dnsControl) PodIndex(ip string) (pods []*object.Pod) { + if dns.podLister == nil { + return nil + } os, err := dns.podLister.ByIndex(podIPIndex, ip) if err != nil { return nil @@ -368,27 +353,24 @@ func (dns *dnsControl) PodIndex(ip string) (pods []*object.Pod) { if !ok { continue } - pods = append(pods, p) + return []*object.Pod{p} } - return pods + return nil } -func (dns *dnsControl) SvcIndex(idx string) (svcs []*object.Service) { - os, err := dns.svcLister.ByIndex(svcNameNamespaceIndex, idx) +func (dns *dnsControl) SvcIndex(key string) *object.Service { + o, _, err := dns.svcLister.GetByKey(key) if err != nil { return nil } - for _, o := range os { - s, ok := o.(*object.Service) - if !ok { - continue - } - svcs = append(svcs, s) + s, ok := o.(*object.Service) + if !ok { + return nil } - return svcs + return s } -func (dns *dnsControl) SvcIndexReverse(ip string) (svcs []*object.Service) { +func (dns *dnsControl) SvcIndexReverse(ip string) *object.Service { os, err := dns.svcLister.ByIndex(svcIPIndex, ip) if err != nil { return nil @@ -399,27 +381,27 @@ func (dns *dnsControl) SvcIndexReverse(ip string) (svcs []*object.Service) { if !ok { continue } - svcs = append(svcs, s) + return s } - return svcs + return nil } -func (dns *dnsControl) EpIndex(idx string) (ep []*object.Endpoints) { - os, err := dns.epLister.ByIndex(epNameNamespaceIndex, idx) +func (dns *dnsControl) EpIndex(key string) (ep *object.Endpoints) { + o, _, err := dns.epLister.GetByKey(key) if err != nil { return nil } - for _, o := range os { - e, ok := o.(*object.Endpoints) - if !ok { - continue - } - ep = append(ep, e) + e, ok := o.(*object.Endpoints) + if !ok { + return nil } - return ep + return e } -func (dns *dnsControl) EpIndexReverse(ip string) (ep []*object.Endpoints) { +func (dns *dnsControl) EpIndexReverse(ip string) (ep *object.Endpoints) { + if dns.epLister == nil { + return nil + } os, err := dns.epLister.ByIndex(epIPIndex, ip) if err != nil { return nil @@ -429,9 +411,9 @@ func (dns *dnsControl) EpIndexReverse(ip string) (ep []*object.Endpoints) { if !ok { continue } - ep = append(ep, e) + return e } - return ep + return nil } // GetNodeByName return the node by name. If nothing is found an error is @@ -450,7 +432,7 @@ func (dns *dnsControl) GetNamespaceByName(name string) (*api.Namespace, error) { if !ok { continue } - if name == ns.ObjectMeta.Name { + if name == ns.GetName() { return ns, nil } } diff --git a/plugin/kubernetes/handler_test.go b/plugin/kubernetes/handler_test.go index 604f00fab..b3353af1b 100644 --- a/plugin/kubernetes/handler_test.go +++ b/plugin/kubernetes/handler_test.go @@ -379,15 +379,15 @@ func TestServeDNS(t *testing.T) { type APIConnServeTest struct{} -func (APIConnServeTest) HasSynced() bool { return true } -func (APIConnServeTest) Run() { return } -func (APIConnServeTest) Stop() error { return nil } -func (APIConnServeTest) EpIndexReverse(string) []*object.Endpoints { return nil } -func (APIConnServeTest) SvcIndexReverse(string) []*object.Service { return nil } -func (APIConnServeTest) Modified() int64 { return time.Now().Unix() } -func (APIConnServeTest) SetWatchChan(watch.Chan) {} -func (APIConnServeTest) Watch(string) error { return nil } -func (APIConnServeTest) StopWatching(string) {} +func (APIConnServeTest) HasSynced() bool { return true } +func (APIConnServeTest) Run() { return } +func (APIConnServeTest) Stop() error { return nil } +func (APIConnServeTest) EpIndexReverse(string) *object.Endpoints { return nil } +func (APIConnServeTest) SvcIndexReverse(string) *object.Service { return nil } +func (APIConnServeTest) Modified() int64 { return time.Now().Unix() } +func (APIConnServeTest) SetWatchChan(watch.Chan) {} +func (APIConnServeTest) Watch(string) error { return nil } +func (APIConnServeTest) StopWatching(string) {} func (APIConnServeTest) PodIndex(string) []*object.Pod { a := []*object.Pod{ @@ -396,103 +396,90 @@ func (APIConnServeTest) PodIndex(string) []*object.Pod { return a } -var svcIndex = map[string][]*object.Service{ - "svc1.testns": { - { - Name: "svc1", - Namespace: "testns", - Type: api.ServiceTypeClusterIP, - ClusterIP: "10.0.0.1", - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, +var svcIndex = map[string]*object.Service{ + "testns/svc1": { + Name: "svc1", + Namespace: "testns", + Type: api.ServiceTypeClusterIP, + ClusterIP: "10.0.0.1", + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, - "svcempty.testns": { - { - Name: "svcempty", - Namespace: "testns", - Type: api.ServiceTypeClusterIP, - ClusterIP: "10.0.0.1", - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, + "testns/svcempty": { + Name: "svcempty", + Namespace: "testns", + Type: api.ServiceTypeClusterIP, + ClusterIP: "10.0.0.1", + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, - "svc6.testns": { - { - Name: "svc6", - Namespace: "testns", - Type: api.ServiceTypeClusterIP, - ClusterIP: "1234:abcd::1", - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, + "testns/svc6": { + Name: "svc6", + Namespace: "testns", + Type: api.ServiceTypeClusterIP, + ClusterIP: "1234:abcd::1", + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, - "hdls1.testns": { - { - Name: "hdls1", - Namespace: "testns", - Type: api.ServiceTypeClusterIP, - ClusterIP: api.ClusterIPNone, + "testns/hdls1": { + Name: "hdls1", + Namespace: "testns", + Type: api.ServiceTypeClusterIP, + ClusterIP: api.ClusterIPNone, + }, + "testns/external": { + + Name: "external", + Namespace: "testns", + ExternalName: "ext.interwebs.test", + Type: api.ServiceTypeExternalName, + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, - "external.testns": { - { - Name: "external", - Namespace: "testns", - ExternalName: "ext.interwebs.test", - Type: api.ServiceTypeExternalName, - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, + "testns/external-to-service": { + Name: "external-to-service", + Namespace: "testns", + ExternalName: "svc1.testns.svc.cluster.local.", + Type: api.ServiceTypeExternalName, + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, - "external-to-service.testns": { - { - Name: "external-to-service", - Namespace: "testns", - ExternalName: "svc1.testns.svc.cluster.local.", - Type: api.ServiceTypeExternalName, - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, - }, + "testns/hdlsprtls": { + Name: "hdlsprtls", + Namespace: "testns", + Type: api.ServiceTypeClusterIP, + ClusterIP: api.ClusterIPNone, }, - "hdlsprtls.testns": { - { - Name: "hdlsprtls", - Namespace: "testns", - Type: api.ServiceTypeClusterIP, - ClusterIP: api.ClusterIPNone, - }, - }, - "svc1.unexposedns": { - { - Name: "svc1", - Namespace: "unexposedns", - Type: api.ServiceTypeClusterIP, - ClusterIP: "10.0.0.2", - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, + "unexposedns/svc1": { + Name: "svc1", + Namespace: "unexposedns", + Type: api.ServiceTypeClusterIP, + ClusterIP: "10.0.0.2", + Ports: []api.ServicePort{ + {Name: "http", Protocol: "tcp", Port: 80}, }, }, } -func (APIConnServeTest) SvcIndex(s string) []*object.Service { return svcIndex[s] } +func (APIConnServeTest) SvcIndex(s string) *object.Service { + return svcIndex[s] +} func (APIConnServeTest) ServiceList() []*object.Service { var svcs []*object.Service for _, svc := range svcIndex { - svcs = append(svcs, svc...) + svcs = append(svcs, svc) } return svcs } -var epsIndex = map[string][]*object.Endpoints{ - "svc1.testns": {{ +var epsIndex = map[string]*object.Endpoints{ + "testns/svc1": { Subsets: []object.EndpointSubset{ { Addresses: []object.EndpointAddress{ @@ -505,8 +492,8 @@ var epsIndex = map[string][]*object.Endpoints{ }, Name: "svc1", Namespace: "testns", - }}, - "svcempty.testns": {{ + }, + "testns/svcempty": { Subsets: []object.EndpointSubset{ { Addresses: nil, @@ -517,8 +504,8 @@ var epsIndex = map[string][]*object.Endpoints{ }, Name: "svcempty", Namespace: "testns", - }}, - "hdls1.testns": {{ + }, + "testns/hdls1": { Subsets: []object.EndpointSubset{ { Addresses: []object.EndpointAddress{ @@ -536,8 +523,8 @@ var epsIndex = map[string][]*object.Endpoints{ }, Name: "hdls1", Namespace: "testns", - }}, - "hdlsprtls.testns": {{ + }, + "testns/hdlsprtls": { Subsets: []object.EndpointSubset{ { Addresses: []object.EndpointAddress{ @@ -548,17 +535,17 @@ var epsIndex = map[string][]*object.Endpoints{ }, Name: "hdlsprtls", Namespace: "testns", - }}, + }, } -func (APIConnServeTest) EpIndex(s string) []*object.Endpoints { +func (APIConnServeTest) EpIndex(s string) *object.Endpoints { return epsIndex[s] } func (APIConnServeTest) EndpointsList() []*object.Endpoints { var eps []*object.Endpoints for _, ep := range epsIndex { - eps = append(eps, ep...) + eps = append(eps, ep) } return eps } diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go index 81cf19492..8ba21a70e 100644 --- a/plugin/kubernetes/kubernetes.go +++ b/plugin/kubernetes/kubernetes.go @@ -444,9 +444,12 @@ func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg. serviceList = k.APIConn.ServiceList() endpointsListFunc = func() []*object.Endpoints { return k.APIConn.EndpointsList() } } else { - idx := object.ServiceKey(r.service, r.namespace) - serviceList = k.APIConn.SvcIndex(idx) - endpointsListFunc = func() []*object.Endpoints { return k.APIConn.EpIndex(idx) } + key := object.ServiceKey(r.namespace, r.service) + s := k.APIConn.SvcIndex(key) + if s != nil { + serviceList = append(serviceList, s) + } + endpointsListFunc = func() []*object.Endpoints { return []*object.Endpoints{k.APIConn.EpIndex(key)} } } for _, svc := range serviceList { diff --git a/plugin/kubernetes/kubernetes_test.go b/plugin/kubernetes/kubernetes_test.go index f35c9cd2c..b8274d01b 100644 --- a/plugin/kubernetes/kubernetes_test.go +++ b/plugin/kubernetes/kubernetes_test.go @@ -59,43 +59,24 @@ func TestEndpointHostname(t *testing.T) { type APIConnServiceTest struct{} -func (APIConnServiceTest) HasSynced() bool { return true } -func (APIConnServiceTest) Run() { return } -func (APIConnServiceTest) Stop() error { return nil } -func (APIConnServiceTest) PodIndex(string) []*object.Pod { return nil } -func (APIConnServiceTest) SvcIndexReverse(string) []*object.Service { return nil } -func (APIConnServiceTest) EpIndexReverse(string) []*object.Endpoints { return nil } -func (APIConnServiceTest) Modified() int64 { return 0 } -func (APIConnServiceTest) SetWatchChan(watch.Chan) {} -func (APIConnServiceTest) Watch(string) error { return nil } -func (APIConnServiceTest) StopWatching(string) {} +func (APIConnServiceTest) HasSynced() bool { return true } +func (APIConnServiceTest) Run() { return } +func (APIConnServiceTest) Stop() error { return nil } +func (APIConnServiceTest) PodIndex(string) []*object.Pod { return nil } +func (APIConnServiceTest) SvcIndexReverse(string) *object.Service { return nil } +func (APIConnServiceTest) EpIndexReverse(string) *object.Endpoints { return nil } +func (APIConnServiceTest) Modified() int64 { return 0 } +func (APIConnServiceTest) SetWatchChan(watch.Chan) {} +func (APIConnServiceTest) Watch(string) error { return nil } +func (APIConnServiceTest) StopWatching(string) {} -func (APIConnServiceTest) SvcIndex(string) []*object.Service { - svcs := []*object.Service{ - { - Name: "svc1", - Namespace: "testns", - ClusterIP: "10.0.0.1", - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, - }, - { - Name: "hdls1", - Namespace: "testns", - ClusterIP: api.ClusterIPNone, - }, - { - Name: "external", - Namespace: "testns", - ExternalName: "coredns.io", - Type: api.ServiceTypeExternalName, - Ports: []api.ServicePort{ - {Name: "http", Protocol: "tcp", Port: 80}, - }, - }, +func (a APIConnServiceTest) SvcIndex(key string) *object.Service { + for _, s := range a.ServiceList() { + if object.ServiceKey(s.Namespace, s.Name) == key { + return s + } } - return svcs + return nil } func (APIConnServiceTest) ServiceList() []*object.Service { @@ -126,61 +107,13 @@ func (APIConnServiceTest) ServiceList() []*object.Service { return svcs } -func (APIConnServiceTest) EpIndex(string) []*object.Endpoints { - eps := []*object.Endpoints{ - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - {IP: "172.0.0.1", Hostname: "ep1a"}, - }, - Ports: []object.EndpointPort{ - {Port: 80, Protocol: "tcp", Name: "http"}, - }, - }, - }, - Name: "svc1", - Namespace: "testns", - }, - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - {IP: "172.0.0.2"}, - }, - Ports: []object.EndpointPort{ - {Port: 80, Protocol: "tcp", Name: "http"}, - }, - }, - }, - Name: "hdls1", - Namespace: "testns", - }, - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - {IP: "172.0.0.3"}, - }, - Ports: []object.EndpointPort{ - {Port: 80, Protocol: "tcp", Name: "http"}, - }, - }, - }, - Name: "hdls1", - Namespace: "testns", - }, - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - {IP: "10.9.8.7", NodeName: "test.node.foo.bar"}, - }, - }, - }, - }, +func (a APIConnServiceTest) EpIndex(key string) *object.Endpoints { + for _, e := range a.EndpointsList() { + if object.EndpointsKey(e.Namespace, e.Name) == key { + return e + } } - return eps + return nil } func (APIConnServiceTest) EndpointsList() []*object.Endpoints { @@ -224,7 +157,7 @@ func (APIConnServiceTest) EndpointsList() []*object.Endpoints { }, }, }, - Name: "hdls1", + Name: "hdls2", Namespace: "testns", }, { @@ -235,6 +168,8 @@ func (APIConnServiceTest) EndpointsList() []*object.Endpoints { }, }, }, + Name: "testsvc", + Namespace: "testns", }, } return eps diff --git a/plugin/kubernetes/local.go b/plugin/kubernetes/local.go index e15fec497..7a85de1bf 100644 --- a/plugin/kubernetes/local.go +++ b/plugin/kubernetes/local.go @@ -28,14 +28,18 @@ func (k *Kubernetes) localNodeName() string { } // Find endpoint matching localIP - for _, ep := range k.APIConn.EpIndexReverse(localIP.String()) { - for _, eps := range ep.Subsets { - for _, addr := range eps.Addresses { - if localIP.Equal(net.ParseIP(addr.IP)) { - return addr.NodeName - } + ep := k.APIConn.EpIndexReverse(localIP.String()) + if ep == nil { + return "" + } + + for _, eps := range ep.Subsets { + for _, addr := range eps.Addresses { + if localIP.Equal(net.ParseIP(addr.IP)) { + return addr.NodeName } } } + return "" } diff --git a/plugin/kubernetes/ns.go b/plugin/kubernetes/ns.go index 2ccb51ef3..722dc9ef4 100644 --- a/plugin/kubernetes/ns.go +++ b/plugin/kubernetes/ns.go @@ -4,6 +4,7 @@ import ( "net" "strings" + "github.com/coredns/coredns/plugin/kubernetes/object" "github.com/miekg/dns" api "k8s.io/api/core/v1" ) @@ -22,8 +23,9 @@ func (k *Kubernetes) nsAddr() *dns.A { localIP := k.interfaceAddrsFunc() rr.A = localIP -FindEndpoint: - for _, ep := range k.APIConn.EpIndexReverse(localIP.String()) { + ep := k.APIConn.EpIndexReverse(localIP.String()) + if ep != nil { + FindEndpoint: for _, eps := range ep.Subsets { for _, addr := range eps.Addresses { if localIP.Equal(net.ParseIP(addr.IP)) { @@ -41,15 +43,12 @@ FindEndpoint: return rr } -FindService: - for _, svc := range k.APIConn.ServiceList() { - if svcName == svc.Name && svcNamespace == svc.Namespace { - if svc.ClusterIP == api.ClusterIPNone { - rr.A = localIP - } else { - rr.A = net.ParseIP(svc.ClusterIP) - } - break FindService + svc := k.APIConn.SvcIndex(object.ServiceKey(svcNamespace, svcName)) + if svc != nil { + if svc.ClusterIP == api.ClusterIPNone { + rr.A = localIP + } else { + rr.A = net.ParseIP(svc.ClusterIP) } } diff --git a/plugin/kubernetes/ns_test.go b/plugin/kubernetes/ns_test.go index fd781bc14..c9025288b 100644 --- a/plugin/kubernetes/ns_test.go +++ b/plugin/kubernetes/ns_test.go @@ -11,18 +11,26 @@ import ( type APIConnTest struct{} -func (APIConnTest) HasSynced() bool { return true } -func (APIConnTest) Run() { return } -func (APIConnTest) Stop() error { return nil } -func (APIConnTest) PodIndex(string) []*object.Pod { return nil } -func (APIConnTest) SvcIndex(string) []*object.Service { return nil } -func (APIConnTest) SvcIndexReverse(string) []*object.Service { return nil } -func (APIConnTest) EpIndex(string) []*object.Endpoints { return nil } -func (APIConnTest) EndpointsList() []*object.Endpoints { return nil } -func (APIConnTest) Modified() int64 { return 0 } -func (APIConnTest) SetWatchChan(watch.Chan) {} -func (APIConnTest) Watch(string) error { return nil } -func (APIConnTest) StopWatching(string) {} +func (APIConnTest) HasSynced() bool { return true } +func (APIConnTest) Run() { return } +func (APIConnTest) Stop() error { return nil } +func (APIConnTest) PodIndex(string) []*object.Pod { return nil } +func (APIConnTest) SvcIndexReverse(string) *object.Service { return nil } +func (APIConnTest) EpIndex(string) *object.Endpoints { return nil } +func (APIConnTest) EndpointsList() []*object.Endpoints { return nil } +func (APIConnTest) Modified() int64 { return 0 } +func (APIConnTest) SetWatchChan(watch.Chan) {} +func (APIConnTest) Watch(string) error { return nil } +func (APIConnTest) StopWatching(string) {} + +func (a APIConnTest) SvcIndex(key string) *object.Service { + for _, s := range a.ServiceList() { + if object.ServiceKey(s.Namespace, s.Name) == key { + return s + } + } + return nil +} func (APIConnTest) ServiceList() []*object.Service { svcs := []*object.Service{ @@ -35,23 +43,21 @@ func (APIConnTest) ServiceList() []*object.Service { return svcs } -func (APIConnTest) EpIndexReverse(string) []*object.Endpoints { - eps := []*object.Endpoints{ - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - { - IP: "127.0.0.1", - }, +func (APIConnTest) EpIndexReverse(string) *object.Endpoints { + eps := object.Endpoints{ + Subsets: []object.EndpointSubset{ + { + Addresses: []object.EndpointAddress{ + { + IP: "127.0.0.1", }, }, }, - Name: "dns-service", - Namespace: "kube-system", }, + Name: "dns-service", + Namespace: "kube-system", } - return eps + return &eps } func (APIConnTest) GetNodeByName(name string) (*api.Node, error) { return &api.Node{}, nil } diff --git a/plugin/kubernetes/object/endpoint.go b/plugin/kubernetes/object/endpoint.go index b8531f050..a391c6426 100644 --- a/plugin/kubernetes/object/endpoint.go +++ b/plugin/kubernetes/object/endpoint.go @@ -40,7 +40,7 @@ type EndpointPort struct { } // EndpointsKey return a string using for the index. -func EndpointsKey(name, namespace string) string { return name + "." + namespace } +func EndpointsKey(namespace, name string) string { return namespace + "/" + name } // ToEndpoints converts an api.Service to a *Service. func ToEndpoints(obj interface{}) interface{} { @@ -61,7 +61,7 @@ func ToEndpoints(obj interface{}) interface{} { Addresses: make([]EndpointAddress, len(eps.Addresses)), } if len(eps.Ports) == 0 { - // Add sentinal if there are no ports. + // Add sentinel if there are no ports. sub.Ports = []EndpointPort{{Port: -1}} } else { sub.Ports = make([]EndpointPort, len(eps.Ports)) diff --git a/plugin/kubernetes/object/service.go b/plugin/kubernetes/object/service.go index be010e96b..1c716b28b 100644 --- a/plugin/kubernetes/object/service.go +++ b/plugin/kubernetes/object/service.go @@ -20,7 +20,7 @@ type Service struct { } // ServiceKey return a string using for the index. -func ServiceKey(name, namespace string) string { return name + "." + namespace } +func ServiceKey(namespace, name string) string { return namespace + "/" + name } // ToService converts an api.Service to a *Service. func ToService(obj interface{}) interface{} { diff --git a/plugin/kubernetes/reverse.go b/plugin/kubernetes/reverse.go index 5873bcbc8..1e060283c 100644 --- a/plugin/kubernetes/reverse.go +++ b/plugin/kubernetes/reverse.go @@ -18,35 +18,35 @@ func (k *Kubernetes) Reverse(state request.Request, exact bool, opt plugin.Optio return nil, e } - records := k.serviceRecordForIP(ip, state.Name()) - if len(records) == 0 { - return records, errNoItems + record := k.serviceRecordForIP(ip, state.Name()) + if record == nil { + return nil, errNoItems } - return records, nil + return []msg.Service{*record}, nil } // serviceRecordForIP gets a service record with a cluster ip matching the ip argument // If a service cluster ip does not match, it checks all endpoints -func (k *Kubernetes) serviceRecordForIP(ip, name string) []msg.Service { +func (k *Kubernetes) serviceRecordForIP(ip, name string) *msg.Service { // First check services with cluster ips - for _, service := range k.APIConn.SvcIndexReverse(ip) { + service := k.APIConn.SvcIndexReverse(ip) + if service != nil { if len(k.Namespaces) > 0 && !k.namespaceExposed(service.Namespace) { - continue + return nil } domain := strings.Join([]string{service.Name, service.Namespace, Svc, k.primaryZone()}, ".") - return []msg.Service{{Host: domain, TTL: k.ttl}} + return &msg.Service{Host: domain, TTL: k.ttl} } // If no cluster ips match, search endpoints - for _, ep := range k.APIConn.EpIndexReverse(ip) { - if len(k.Namespaces) > 0 && !k.namespaceExposed(ep.Namespace) { - continue - } - for _, eps := range ep.Subsets { - for _, addr := range eps.Addresses { - if addr.IP == ip { - domain := strings.Join([]string{endpointHostname(addr, k.endpointNameMode), ep.Name, ep.Namespace, Svc, k.primaryZone()}, ".") - return []msg.Service{{Host: domain, TTL: k.ttl}} - } + ep := k.APIConn.EpIndexReverse(ip) + if ep == nil || len(k.Namespaces) > 0 && !k.namespaceExposed(ep.Namespace) { + return nil + } + for _, eps := range ep.Subsets { + for _, addr := range eps.Addresses { + if addr.IP == ip { + domain := strings.Join([]string{endpointHostname(addr, k.endpointNameMode), ep.Name, ep.Namespace, Svc, k.primaryZone()}, ".") + return &msg.Service{Host: domain, TTL: k.ttl} } } } diff --git a/plugin/kubernetes/reverse_test.go b/plugin/kubernetes/reverse_test.go index a706b7585..20c8496c7 100644 --- a/plugin/kubernetes/reverse_test.go +++ b/plugin/kubernetes/reverse_test.go @@ -20,7 +20,7 @@ func (APIConnReverseTest) HasSynced() bool { return true } func (APIConnReverseTest) Run() { return } func (APIConnReverseTest) Stop() error { return nil } func (APIConnReverseTest) PodIndex(string) []*object.Pod { return nil } -func (APIConnReverseTest) EpIndex(string) []*object.Endpoints { return nil } +func (APIConnReverseTest) EpIndex(string) *object.Endpoints { return nil } func (APIConnReverseTest) EndpointsList() []*object.Endpoints { return nil } func (APIConnReverseTest) ServiceList() []*object.Service { return nil } func (APIConnReverseTest) Modified() int64 { return 0 } @@ -28,38 +28,34 @@ func (APIConnReverseTest) SetWatchChan(watch.Chan) {} func (APIConnReverseTest) Watch(string) error { return nil } func (APIConnReverseTest) StopWatching(string) {} -func (APIConnReverseTest) SvcIndex(svc string) []*object.Service { - if svc != "svc1.testns" { +func (APIConnReverseTest) SvcIndex(key string) *object.Service { + if key != "testns/svc1" { return nil } - svcs := []*object.Service{ - { - Name: "svc1", - Namespace: "testns", - ClusterIP: "192.168.1.100", - Ports: []api.ServicePort{{Name: "http", Protocol: "tcp", Port: 80}}, - }, + svc := object.Service{ + Name: "svc1", + Namespace: "testns", + ClusterIP: "192.168.1.100", + Ports: []api.ServicePort{{Name: "http", Protocol: "tcp", Port: 80}}, } - return svcs + return &svc } -func (APIConnReverseTest) SvcIndexReverse(ip string) []*object.Service { +func (APIConnReverseTest) SvcIndexReverse(ip string) *object.Service { if ip != "192.168.1.100" { return nil } - svcs := []*object.Service{ - { - Name: "svc1", - Namespace: "testns", - ClusterIP: "192.168.1.100", - Ports: []api.ServicePort{{Name: "http", Protocol: "tcp", Port: 80}}, - }, + svc := object.Service{ + Name: "svc1", + Namespace: "testns", + ClusterIP: "192.168.1.100", + Ports: []api.ServicePort{{Name: "http", Protocol: "tcp", Port: 80}}, } - return svcs + return &svc } -func (APIConnReverseTest) EpIndexReverse(ip string) []*object.Endpoints { +func (APIConnReverseTest) EpIndexReverse(ip string) *object.Endpoints { switch ip { case "10.0.0.100": case "1234:abcd::1": @@ -68,26 +64,24 @@ func (APIConnReverseTest) EpIndexReverse(ip string) []*object.Endpoints { default: return nil } - eps := []*object.Endpoints{ - { - Subsets: []object.EndpointSubset{ - { - Addresses: []object.EndpointAddress{ - {IP: "10.0.0.100", Hostname: "ep1a"}, - {IP: "1234:abcd::1", Hostname: "ep1b"}, - {IP: "fd00:77:30::a", Hostname: "ip6svc1ex"}, - {IP: "fd00:77:30::2:9ba6", Hostname: "ip6svc1in"}, - }, - Ports: []object.EndpointPort{ - {Port: 80, Protocol: "tcp", Name: "http"}, - }, + ep := object.Endpoints{ + Subsets: []object.EndpointSubset{ + { + Addresses: []object.EndpointAddress{ + {IP: "10.0.0.100", Hostname: "ep1a"}, + {IP: "1234:abcd::1", Hostname: "ep1b"}, + {IP: "fd00:77:30::a", Hostname: "ip6svc1ex"}, + {IP: "fd00:77:30::2:9ba6", Hostname: "ip6svc1in"}, + }, + Ports: []object.EndpointPort{ + {Port: 80, Protocol: "tcp", Name: "http"}, }, }, - Name: "svc1", - Namespace: "testns", }, + Name: "svc1", + Namespace: "testns", } - return eps + return &ep } func (APIConnReverseTest) GetNodeByName(name string) (*api.Node, error) { diff --git a/plugin/kubernetes/xfr.go b/plugin/kubernetes/xfr.go index eaf554c6a..b76e1def9 100644 --- a/plugin/kubernetes/xfr.go +++ b/plugin/kubernetes/xfr.go @@ -9,6 +9,7 @@ import ( "github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin/etcd/msg" "github.com/coredns/coredns/request" + "k8s.io/client-go/tools/cache" "github.com/miekg/dns" api "k8s.io/api/core/v1" @@ -114,39 +115,36 @@ func (k *Kubernetes) transfer(c chan dns.RR, zone string) { continue } - endpointsList := k.APIConn.EpIndex(svc.Name + "." + svc.Namespace) + key, err := cache.MetaNamespaceKeyFunc(svc) + if err != nil { + return + } + ep := k.APIConn.EpIndex(key) + for _, eps := range ep.Subsets { + srvWeight := calcSRVWeight(len(eps.Addresses)) + for _, addr := range eps.Addresses { + s := msg.Service{Host: addr.IP, TTL: k.ttl} + s.Key = strings.Join(svcBase, "/") + // We don't need to change the msg.Service host from IP to Name yet + // so disregard the return value here + emitAddressRecord(c, s) - for _, ep := range endpointsList { - if ep.Name != svc.Name || ep.Namespace != svc.Namespace { - continue - } + s.Key = strings.Join(append(svcBase, endpointHostname(addr, k.endpointNameMode)), "/") + // Change host from IP to Name for SRV records + host := emitAddressRecord(c, s) + s.Host = host - for _, eps := range ep.Subsets { - srvWeight := calcSRVWeight(len(eps.Addresses)) - for _, addr := range eps.Addresses { - s := msg.Service{Host: addr.IP, TTL: k.ttl} - s.Key = strings.Join(svcBase, "/") - // We don't need to change the msg.Service host from IP to Name yet - // so disregard the return value here - emitAddressRecord(c, s) - - s.Key = strings.Join(append(svcBase, endpointHostname(addr, k.endpointNameMode)), "/") - // Change host from IP to Name for SRV records - host := emitAddressRecord(c, s) - s.Host = host - - for _, p := range eps.Ports { - // As per spec unnamed ports do not have a srv record - // https://github.com/kubernetes/dns/blob/master/docs/specification.md#232---srv-records - if p.Name == "" { - continue - } - - s.Port = int(p.Port) - - s.Key = strings.Join(append(svcBase, strings.ToLower("_"+string(p.Protocol)), strings.ToLower("_"+string(p.Name))), "/") - c <- s.NewSRV(msg.Domain(s.Key), srvWeight) + for _, p := range eps.Ports { + // As per spec unnamed ports do not have a srv record + // https://github.com/kubernetes/dns/blob/master/docs/specification.md#232---srv-records + if p.Name == "" { + continue } + + s.Port = int(p.Port) + + s.Key = strings.Join(append(svcBase, strings.ToLower("_"+string(p.Protocol)), strings.ToLower("_"+string(p.Name))), "/") + c <- s.NewSRV(msg.Domain(s.Key), srvWeight) } } }