mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	mw/kubernetes: remove kService and kPod
Remove the intermediate step of gathering everyhing in a kPod and kService and extracting the msg.Service from there. Now findPods and findServices return []msg.Service. This cuts down on the code and also removed the double looping of finding the data we need, so it should be faster.
This commit is contained in:
		| @@ -30,7 +30,7 @@ func (k *Kubernetes) Federations(state request.Request, fname, fzone string) (ms | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return msg.Service{}, err | 		return msg.Service{}, err | ||||||
| 	} | 	} | ||||||
| 	r, err := k.parseRequest(state) | 	r, err := parseRequest(state) | ||||||
|  |  | ||||||
| 	lz := node.Labels[LabelZone] | 	lz := node.Labels[LabelZone] | ||||||
| 	lr := node.Labels[LabelRegion] | 	lr := node.Labels[LabelRegion] | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ var dnsTestCases = map[string](test.Case){ | |||||||
| 	}, | 	}, | ||||||
| 	"SRV Service Not udp/tcp": { | 	"SRV Service Not udp/tcp": { | ||||||
| 		Qname: "*._not-udp-or-tcp.svc1.testns.svc.cluster.local.", Qtype: dns.TypeSRV, | 		Qname: "*._not-udp-or-tcp.svc1.testns.svc.cluster.local.", Qtype: dns.TypeSRV, | ||||||
| 		Rcode: dns.RcodeSuccess, | 		Rcode: dns.RcodeNameError, | ||||||
| 		Ns: []dns.RR{ | 		Ns: []dns.RR{ | ||||||
| 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
| 		}, | 		}, | ||||||
| @@ -105,6 +105,14 @@ var dnsTestCases = map[string](test.Case){ | |||||||
| 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  | 	"A Service (non-existing service)": { | ||||||
|  | 		Qname: "svc0.testns.svc.cluster.local.", Qtype: dns.TypeA, | ||||||
|  | 		Rcode:  dns.RcodeNameError, | ||||||
|  | 		Answer: []dns.RR{}, | ||||||
|  | 		Ns: []dns.RR{ | ||||||
|  | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
| 	"TXT Schema": { | 	"TXT Schema": { | ||||||
| 		Qname: "dns-version.cluster.local.", Qtype: dns.TypeTXT, | 		Qname: "dns-version.cluster.local.", Qtype: dns.TypeTXT, | ||||||
| 		Rcode: dns.RcodeSuccess, | 		Rcode: dns.RcodeSuccess, | ||||||
|   | |||||||
| @@ -75,27 +75,6 @@ const ( | |||||||
| 	DNSSchemaVersion = "1.0.1" | 	DNSSchemaVersion = "1.0.1" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type endpoint struct { |  | ||||||
| 	addr api.EndpointAddress |  | ||||||
| 	port api.EndpointPort |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // kService is a service as retrieved via the k8s API. |  | ||||||
| type kService struct { |  | ||||||
| 	name      string |  | ||||||
| 	namespace string |  | ||||||
| 	addr      string |  | ||||||
| 	ports     []api.ServicePort |  | ||||||
| 	endpoints []endpoint |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // kPod is a pod as retrieved via the k8s API. |  | ||||||
| type kPod struct { |  | ||||||
| 	name      string |  | ||||||
| 	namespace string |  | ||||||
| 	addr      string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	errNoItems        = errors.New("no items found") | 	errNoItems        = errors.New("no items found") | ||||||
| 	errNsNotExposed   = errors.New("namespace is not exposed") | 	errNsNotExposed   = errors.New("namespace is not exposed") | ||||||
| @@ -301,7 +280,7 @@ func (k *Kubernetes) Records(name string, exact bool) ([]msg.Service, error) { | |||||||
|  |  | ||||||
| // Entries looks up services in kubernetes. | // Entries looks up services in kubernetes. | ||||||
| func (k *Kubernetes) Entries(state request.Request) ([]msg.Service, error) { | func (k *Kubernetes) Entries(state request.Request) ([]msg.Service, error) { | ||||||
| 	r, e := k.parseRequest(state) | 	r, e := parseRequest(state) | ||||||
| 	if e != nil { | 	if e != nil { | ||||||
| 		return nil, e | 		return nil, e | ||||||
| 	} | 	} | ||||||
| @@ -310,16 +289,13 @@ func (k *Kubernetes) Entries(state request.Request) ([]msg.Service, error) { | |||||||
| 		return nil, errNsNotExposed | 		return nil, errNsNotExposed | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	services, pods, err := k.get(r) | 	if r.podOrSvc == Pod { | ||||||
| 	if err != nil { | 		pods, err := k.findPods(r, state.Zone) | ||||||
| 		return nil, err | 		return pods, err | ||||||
| 	} |  | ||||||
| 	if len(services) == 0 && len(pods) == 0 { |  | ||||||
| 		return nil, errNoItems |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	records := k.getRecordsForK8sItems(services, pods, state.Zone) | 	services, err := k.findServices(r, state.Zone) | ||||||
| 	return records, nil | 	return services, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func endpointHostname(addr api.EndpointAddress) string { | func endpointHostname(addr api.EndpointAddress) string { | ||||||
| @@ -335,51 +311,18 @@ func endpointHostname(addr api.EndpointAddress) string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (k *Kubernetes) getRecordsForK8sItems(services []kService, pods []kPod, zone string) (records []msg.Service) { | // findPods returns the pods matching r from the cache. | ||||||
| 	zonePath := msg.Path(zone, "coredns") | func (k *Kubernetes) findPods(r recordRequest, zone string) (pods []msg.Service, err error) { | ||||||
|  |  | ||||||
| 	for _, svc := range services { |  | ||||||
| 		if svc.addr == api.ClusterIPNone || len(svc.endpoints) > 0 { |  | ||||||
| 			// This is a headless service or endpoints are present, create records for each endpoint |  | ||||||
| 			for _, ep := range svc.endpoints { |  | ||||||
| 				s := msg.Service{Host: ep.addr.IP, Port: int(ep.port.Port)} |  | ||||||
| 				s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name, endpointHostname(ep.addr)}, "/") |  | ||||||
|  |  | ||||||
| 				records = append(records, s) |  | ||||||
| 			} |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Create records for each exposed port... |  | ||||||
| 		for _, p := range svc.ports { |  | ||||||
| 			s := msg.Service{Host: svc.addr, Port: int(p.Port)} |  | ||||||
| 			s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/") |  | ||||||
|  |  | ||||||
| 			records = append(records, s) |  | ||||||
| 		} |  | ||||||
| 		// If the addr is not an IP (i.e. an external service), add the record ... |  | ||||||
| 		s := msg.Service{Key: strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/"), Host: svc.addr} |  | ||||||
| 		if t, _ := s.HostType(); t == dns.TypeCNAME { |  | ||||||
| 			s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/") |  | ||||||
|  |  | ||||||
| 			records = append(records, s) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, p := range pods { |  | ||||||
| 		s := msg.Service{Key: strings.Join([]string{zonePath, Pod, p.namespace, p.name}, "/"), Host: p.addr} |  | ||||||
| 		records = append(records, s) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return records |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (k *Kubernetes) findPods(namespace, podname string) (pods []kPod, err error) { |  | ||||||
| 	if k.PodMode == PodModeDisabled { | 	if k.PodMode == PodModeDisabled { | ||||||
| 		return pods, errPodsDisabled | 		return nil, errPodsDisabled | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var ip string | 	namespace := r.namespace | ||||||
|  | 	podname := r.service | ||||||
|  | 	zonePath := msg.Path(zone, "coredns") | ||||||
|  | 	ip := "" | ||||||
|  | 	err = errNoItems | ||||||
|  |  | ||||||
| 	if strings.Count(podname, "-") == 3 && !strings.Contains(podname, "--") { | 	if strings.Count(podname, "-") == 3 && !strings.Contains(podname, "--") { | ||||||
| 		ip = strings.Replace(podname, "-", ".", -1) | 		ip = strings.Replace(podname, "-", ".", -1) | ||||||
| 	} else { | 	} else { | ||||||
| @@ -387,9 +330,7 @@ func (k *Kubernetes) findPods(namespace, podname string) (pods []kPod, err error | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if k.PodMode == PodModeInsecure { | 	if k.PodMode == PodModeInsecure { | ||||||
| 		s := kPod{name: podname, namespace: namespace, addr: ip} | 		return []msg.Service{{Key: strings.Join([]string{zonePath, Pod, namespace, podname}, "/"), Host: ip}}, nil | ||||||
| 		pods = append(pods, s) |  | ||||||
| 		return pods, nil |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// PodModeVerified | 	// PodModeVerified | ||||||
| @@ -406,29 +347,20 @@ func (k *Kubernetes) findPods(namespace, podname string) (pods []kPod, err error | |||||||
| 		} | 		} | ||||||
| 		// check for matching ip and namespace | 		// check for matching ip and namespace | ||||||
| 		if ip == p.Status.PodIP && match(namespace, p.Namespace) { | 		if ip == p.Status.PodIP && match(namespace, p.Namespace) { | ||||||
| 			s := kPod{name: podname, namespace: namespace, addr: ip} | 			s := msg.Service{Key: strings.Join([]string{zonePath, Pod, namespace, podname}, "/"), Host: ip} | ||||||
| 			pods = append(pods, s) | 			pods = append(pods, s) | ||||||
| 			return pods, nil |  | ||||||
|  | 			err = nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return pods, nil | 	return pods, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // get retrieves matching data from the cache. | // findServices returns the services matching r from the cache. | ||||||
| func (k *Kubernetes) get(r recordRequest) (services []kService, pods []kPod, err error) { | func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg.Service, err error) { | ||||||
| 	switch r.podOrSvc { |  | ||||||
| 	case Pod: |  | ||||||
| 		pods, err = k.findPods(r.namespace, r.service) |  | ||||||
| 		return nil, pods, err |  | ||||||
| 	default: |  | ||||||
| 		services, err = k.findServices(r) |  | ||||||
| 		return services, nil, err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (k *Kubernetes) findServices(r recordRequest) ([]kService, error) { |  | ||||||
| 	serviceList := k.APIConn.ServiceList() | 	serviceList := k.APIConn.ServiceList() | ||||||
| 	var resultItems []kService | 	zonePath := msg.Path(zone, "coredns") | ||||||
|  | 	err = errNoItems // Set to errNoItems to signal really nothing found, gets reset when name is matched. | ||||||
|  |  | ||||||
| 	for _, svc := range serviceList { | 	for _, svc := range serviceList { | ||||||
| 		if !(match(r.namespace, svc.Namespace) && match(r.service, svc.Name)) { | 		if !(match(r.namespace, svc.Namespace) && match(r.service, svc.Name)) { | ||||||
| @@ -440,17 +372,17 @@ func (k *Kubernetes) findServices(r recordRequest) ([]kService, error) { | |||||||
| 		if wildcard(r.namespace) && !k.namespaceExposed(svc.Namespace) { | 		if wildcard(r.namespace) && !k.namespaceExposed(svc.Namespace) { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		s := kService{name: svc.Name, namespace: svc.Namespace} |  | ||||||
|  |  | ||||||
| 		// Endpoint query or headless service | 		// Endpoint query or headless service | ||||||
| 		if svc.Spec.ClusterIP == api.ClusterIPNone || r.endpoint != "" { | 		if svc.Spec.ClusterIP == api.ClusterIPNone || r.endpoint != "" { | ||||||
| 			s.addr = svc.Spec.ClusterIP |  | ||||||
| 			endpointsList := k.APIConn.EndpointsList() | 			endpointsList := k.APIConn.EndpointsList() | ||||||
| 			for _, ep := range endpointsList.Items { | 			for _, ep := range endpointsList.Items { | ||||||
| 				if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace { | 				if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace { | ||||||
| 					continue | 					continue | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | 				err = nil | ||||||
|  |  | ||||||
| 				for _, eps := range ep.Subsets { | 				for _, eps := range ep.Subsets { | ||||||
| 					for _, addr := range eps.Addresses { | 					for _, addr := range eps.Addresses { | ||||||
|  |  | ||||||
| @@ -466,36 +398,45 @@ func (k *Kubernetes) findServices(r recordRequest) ([]kService, error) { | |||||||
| 							if !(match(r.port, p.Name) && match(r.protocol, string(p.Protocol))) { | 							if !(match(r.port, p.Name) && match(r.protocol, string(p.Protocol))) { | ||||||
| 								continue | 								continue | ||||||
| 							} | 							} | ||||||
| 							s.endpoints = append(s.endpoints, endpoint{addr: addr, port: p}) | 							s := msg.Service{Host: addr.IP, Port: int(p.Port)} | ||||||
|  | 							s.Key = strings.Join([]string{zonePath, Svc, svc.Namespace, svc.Name, endpointHostname(addr)}, "/") | ||||||
|  |  | ||||||
|  | 							services = append(services, s) | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			if len(s.endpoints) > 0 { |  | ||||||
| 				resultItems = append(resultItems, s) |  | ||||||
| 			} |  | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// External service | 		// External service | ||||||
| 		if svc.Spec.ExternalName != "" { | 		if svc.Spec.ExternalName != "" { | ||||||
| 			s.addr = svc.Spec.ExternalName | 			s := msg.Service{Key: strings.Join([]string{zonePath, Svc, svc.Namespace, svc.Name}, "/"), Host: svc.Spec.ExternalName} | ||||||
| 			resultItems = append(resultItems, s) | 			if t, _ := s.HostType(); t == dns.TypeCNAME { | ||||||
|  | 				s.Key = strings.Join([]string{zonePath, Svc, svc.Namespace, svc.Name}, "/") | ||||||
|  | 				services = append(services, s) | ||||||
|  |  | ||||||
|  | 				err = nil | ||||||
|  |  | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// ClusterIP service | 		// ClusterIP service | ||||||
| 		s.addr = svc.Spec.ClusterIP |  | ||||||
| 		for _, p := range svc.Spec.Ports { | 		for _, p := range svc.Spec.Ports { | ||||||
| 			if !(match(r.port, p.Name) && match(r.protocol, string(p.Protocol))) { | 			if !(match(r.port, p.Name) && match(r.protocol, string(p.Protocol))) { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			s.ports = append(s.ports, p) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		resultItems = append(resultItems, s) | 			err = nil | ||||||
|  |  | ||||||
|  | 			s := msg.Service{Host: svc.Spec.ClusterIP, Port: int(p.Port)} | ||||||
|  | 			s.Key = strings.Join([]string{zonePath, Svc, svc.Namespace, svc.Name}, "/") | ||||||
|  |  | ||||||
|  | 			services = append(services, s) | ||||||
| 		} | 		} | ||||||
| 	return resultItems, nil | 	} | ||||||
|  | 	return services, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // match checks if a and b are equal taking wildcards into account. | // match checks if a and b are equal taking wildcards into account. | ||||||
| @@ -514,39 +455,6 @@ func wildcard(s string) bool { | |||||||
| 	return s == "*" || s == "any" | 	return s == "*" || s == "any" | ||||||
| } | } | ||||||
|  |  | ||||||
| // 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 { |  | ||||||
| 	// First check services with cluster ips |  | ||||||
| 	svcList := k.APIConn.ServiceList() |  | ||||||
|  |  | ||||||
| 	for _, service := range svcList { |  | ||||||
| 		if (len(k.Namespaces) > 0) && !k.namespaceExposed(service.Namespace) { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if service.Spec.ClusterIP == ip { |  | ||||||
| 			domain := strings.Join([]string{service.Name, service.Namespace, Svc, k.primaryZone()}, ".") |  | ||||||
| 			return []msg.Service{{Host: domain}} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	// If no cluster ips match, search endpoints |  | ||||||
| 	epList := k.APIConn.EndpointsList() |  | ||||||
| 	for _, ep := range epList.Items { |  | ||||||
| 		if (len(k.Namespaces) > 0) && !k.namespaceExposed(ep.ObjectMeta.Namespace) { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		for _, eps := range ep.Subsets { |  | ||||||
| 			for _, addr := range eps.Addresses { |  | ||||||
| 				if addr.IP == ip { |  | ||||||
| 					domain := strings.Join([]string{endpointHostname(addr), ep.ObjectMeta.Name, ep.ObjectMeta.Namespace, Svc, k.primaryZone()}, ".") |  | ||||||
| 					return []msg.Service{{Host: domain}} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // namespaceExposed returns true when the namespace is exposed. | // namespaceExposed returns true when the namespace is exposed. | ||||||
| func (k *Kubernetes) namespaceExposed(namespace string) bool { | func (k *Kubernetes) namespaceExposed(namespace string) bool { | ||||||
| 	_, ok := k.Namespaces[namespace] | 	_, ok := k.Namespaces[namespace] | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ type recordRequest struct { | |||||||
| // parseRequest parses the qname to find all the elements we need for querying k8s. Anything | // parseRequest parses the qname to find all the elements we need for querying k8s. Anything | ||||||
| // that is not parsed will have the wildcard "*" value (except r.endpoint). | // that is not parsed will have the wildcard "*" value (except r.endpoint). | ||||||
| // Potential underscores are stripped from _port and _protocol. | // Potential underscores are stripped from _port and _protocol. | ||||||
| func (k *Kubernetes) parseRequest(state request.Request) (r recordRequest, err error) { | func parseRequest(state request.Request) (r recordRequest, err error) { | ||||||
| 	// 3 Possible cases: | 	// 3 Possible cases: | ||||||
| 	// 1. _port._protocol.service.namespace.pod|svc.zone | 	// 1. _port._protocol.service.namespace.pod|svc.zone | ||||||
| 	// 2. (endpoint): endpoint.service.namespace.pod|svc.zone | 	// 2. (endpoint): endpoint.service.namespace.pod|svc.zone | ||||||
|   | |||||||
| @@ -9,8 +9,6 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestParseRequest(t *testing.T) { | func TestParseRequest(t *testing.T) { | ||||||
| 	k := New([]string{zone}) |  | ||||||
|  |  | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		query    string | 		query    string | ||||||
| 		expected string // output from r.String() | 		expected string // output from r.String() | ||||||
| @@ -27,7 +25,7 @@ func TestParseRequest(t *testing.T) { | |||||||
| 		m.SetQuestion(tc.query, dns.TypeA) | 		m.SetQuestion(tc.query, dns.TypeA) | ||||||
| 		state := request.Request{Zone: zone, Req: m} | 		state := request.Request{Zone: zone, Req: m} | ||||||
|  |  | ||||||
| 		r, e := k.parseRequest(state) | 		r, e := parseRequest(state) | ||||||
| 		if e != nil { | 		if e != nil { | ||||||
| 			t.Errorf("Test %d, expected no error, got '%v'.", i, e) | 			t.Errorf("Test %d, expected no error, got '%v'.", i, e) | ||||||
| 		} | 		} | ||||||
| @@ -39,8 +37,6 @@ func TestParseRequest(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func TestParseInvalidRequest(t *testing.T) { | func TestParseInvalidRequest(t *testing.T) { | ||||||
| 	k := New([]string{zone}) |  | ||||||
|  |  | ||||||
| 	invalid := []string{ | 	invalid := []string{ | ||||||
| 		"webs.mynamespace.pood.inter.webs.test.",                 // Request must be for pod or svc subdomain. | 		"webs.mynamespace.pood.inter.webs.test.",                 // Request must be for pod or svc subdomain. | ||||||
| 		"too.long.for.what.I.am.trying.to.pod.inter.webs.tests.", // Too long. | 		"too.long.for.what.I.am.trying.to.pod.inter.webs.tests.", // Too long. | ||||||
| @@ -51,7 +47,7 @@ func TestParseInvalidRequest(t *testing.T) { | |||||||
| 		m.SetQuestion(query, dns.TypeA) | 		m.SetQuestion(query, dns.TypeA) | ||||||
| 		state := request.Request{Zone: zone, Req: m} | 		state := request.Request{Zone: zone, Req: m} | ||||||
|  |  | ||||||
| 		if _, e := k.parseRequest(state); e == nil { | 		if _, e := parseRequest(state); e == nil { | ||||||
| 			t.Errorf("Test %d: expected error from %s, got none", i, query) | 			t.Errorf("Test %d: expected error from %s, got none", i, query) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| package kubernetes | package kubernetes | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/coredns/coredns/middleware" | 	"github.com/coredns/coredns/middleware" | ||||||
| 	"github.com/coredns/coredns/middleware/etcd/msg" | 	"github.com/coredns/coredns/middleware/etcd/msg" | ||||||
| 	"github.com/coredns/coredns/middleware/pkg/dnsutil" | 	"github.com/coredns/coredns/middleware/pkg/dnsutil" | ||||||
| @@ -18,3 +20,36 @@ func (k *Kubernetes) Reverse(state request.Request, exact bool, opt middleware.O | |||||||
| 	records := k.serviceRecordForIP(ip, state.Name()) | 	records := k.serviceRecordForIP(ip, state.Name()) | ||||||
| 	return records, nil, nil | 	return records, nil, 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 { | ||||||
|  | 	// First check services with cluster ips | ||||||
|  | 	svcList := k.APIConn.ServiceList() | ||||||
|  |  | ||||||
|  | 	for _, service := range svcList { | ||||||
|  | 		if (len(k.Namespaces) > 0) && !k.namespaceExposed(service.Namespace) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if service.Spec.ClusterIP == ip { | ||||||
|  | 			domain := strings.Join([]string{service.Name, service.Namespace, Svc, k.primaryZone()}, ".") | ||||||
|  | 			return []msg.Service{{Host: domain}} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// If no cluster ips match, search endpoints | ||||||
|  | 	epList := k.APIConn.EndpointsList() | ||||||
|  | 	for _, ep := range epList.Items { | ||||||
|  | 		if (len(k.Namespaces) > 0) && !k.namespaceExposed(ep.ObjectMeta.Namespace) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		for _, eps := range ep.Subsets { | ||||||
|  | 			for _, addr := range eps.Addresses { | ||||||
|  | 				if addr.IP == ip { | ||||||
|  | 					domain := strings.Join([]string{endpointHostname(addr), ep.ObjectMeta.Name, ep.ObjectMeta.Namespace, Svc, k.primaryZone()}, ".") | ||||||
|  | 					return []msg.Service{{Host: domain}} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user