mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	plugin/kubernetes: correctly set NODATA for ns (#1229)
* plugin/kubernetes: Add GetNamespaceByName A bare or wildcard query for just the namespace should return NODATA, not NXDOMAIN, otherwise we deny the entirety of the names under the namespace. Add test to check for this in pod verified mode. * Review More comments and move namespace code to namespace.go
This commit is contained in:
		| @@ -36,6 +36,7 @@ type dnsController interface { | |||||||
| 	EndpointsList() []*api.Endpoints | 	EndpointsList() []*api.Endpoints | ||||||
|  |  | ||||||
| 	GetNodeByName(string) (*api.Node, error) | 	GetNodeByName(string) (*api.Node, error) | ||||||
|  | 	GetNamespaceByName(string) (*api.Namespace, error) | ||||||
|  |  | ||||||
| 	Run() | 	Run() | ||||||
| 	HasSynced() bool | 	HasSynced() bool | ||||||
| @@ -388,6 +389,9 @@ func (dns *dnsControl) EndpointsList() (eps []*api.Endpoints) { | |||||||
| 	return eps | 	return eps | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // GetNodeByName return the node by name. If nothing is found an error is | ||||||
|  | // returned. This query causes a roundtrip to the k8s API server, so use | ||||||
|  | // sparingly. Currently this is only used for Federation. | ||||||
| func (dns *dnsControl) GetNodeByName(name string) (*api.Node, error) { | func (dns *dnsControl) GetNodeByName(name string) (*api.Node, error) { | ||||||
| 	v1node, err := dns.client.Nodes().Get(name, meta.GetOptions{}) | 	v1node, err := dns.client.Nodes().Get(name, meta.GetOptions{}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -395,3 +399,14 @@ func (dns *dnsControl) GetNodeByName(name string) (*api.Node, error) { | |||||||
| 	} | 	} | ||||||
| 	return v1node, nil | 	return v1node, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // GetNamespaceByName returns the namespace by name. If nothing is found an | ||||||
|  | // error is returned. This query causes a roundtrip to the k8s API server, so | ||||||
|  | // use sparingly. | ||||||
|  | func (dns *dnsControl) GetNamespaceByName(name string) (*api.Namespace, error) { | ||||||
|  | 	v1ns, err := dns.client.Namespaces().Get(name, meta.GetOptions{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return &api.Namespace{}, err | ||||||
|  | 	} | ||||||
|  | 	return v1ns, nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -18,6 +18,27 @@ var podModeVerifiedCases = []test.Case{ | |||||||
| 			test.A("10-240-0-1.podns.pod.cluster.local.	0	IN	A	10.240.0.1"), | 			test.A("10-240-0-1.podns.pod.cluster.local.	0	IN	A	10.240.0.1"), | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		Qname: "podns.pod.cluster.local.", Qtype: dns.TypeA, | ||||||
|  | 		Rcode: dns.RcodeSuccess, | ||||||
|  | 		Ns: []dns.RR{ | ||||||
|  | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		Qname: "svcns.svc.cluster.local.", Qtype: dns.TypeA, | ||||||
|  | 		Rcode: dns.RcodeSuccess, | ||||||
|  | 		Ns: []dns.RR{ | ||||||
|  | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		Qname: "pod-nons.pod.cluster.local.", Qtype: dns.TypeA, | ||||||
|  | 		Rcode: dns.RcodeNameError, | ||||||
|  | 		Ns: []dns.RR{ | ||||||
|  | 			test.SOA("cluster.local.	300	IN	SOA	ns.dns.cluster.local. hostmaster.cluster.local. 1499347823 7200 1800 86400 60"), | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		Qname: "172-0-0-2.podns.pod.cluster.local.", Qtype: dns.TypeA, | 		Qname: "172-0-0-2.podns.pod.cluster.local.", Qtype: dns.TypeA, | ||||||
| 		Rcode: dns.RcodeNameError, | 		Rcode: dns.RcodeNameError, | ||||||
|   | |||||||
| @@ -476,3 +476,14 @@ func (APIConnServeTest) GetNodeByName(name string) (*api.Node, error) { | |||||||
| 		}, | 		}, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (APIConnServeTest) GetNamespaceByName(name string) (*api.Namespace, error) { | ||||||
|  | 	if name == "pod-nons" { // hanlder_pod_verified_test.go uses this for non-existent namespace. | ||||||
|  | 		return &api.Namespace{}, nil | ||||||
|  | 	} | ||||||
|  | 	return &api.Namespace{ | ||||||
|  | 		ObjectMeta: meta.ObjectMeta{ | ||||||
|  | 			Name: name, | ||||||
|  | 		}, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -304,7 +304,14 @@ func (k *Kubernetes) findPods(r recordRequest, zone string) (pods []msg.Service, | |||||||
| 	podname := r.service | 	podname := r.service | ||||||
| 	zonePath := msg.Path(zone, "coredns") | 	zonePath := msg.Path(zone, "coredns") | ||||||
| 	ip := "" | 	ip := "" | ||||||
|  |  | ||||||
| 	err = errNoItems | 	err = errNoItems | ||||||
|  | 	if wildcard(podname) && !wildcard(namespace) { | ||||||
|  | 		// If namespace exist, err should be nil, so that we return nodata instead of NXDOMAIN | ||||||
|  | 		if k.namespace(namespace) { | ||||||
|  | 			err = nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	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) | ||||||
| @@ -336,7 +343,14 @@ func (k *Kubernetes) findPods(r recordRequest, zone string) (pods []msg.Service, | |||||||
| // findServices returns the services matching r from the cache. | // findServices returns the services matching r from the cache. | ||||||
| func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg.Service, err error) { | func (k *Kubernetes) findServices(r recordRequest, zone string) (services []msg.Service, err error) { | ||||||
| 	zonePath := msg.Path(zone, "coredns") | 	zonePath := msg.Path(zone, "coredns") | ||||||
| 	err = errNoItems // Set to errNoItems to signal really nothing found, gets reset when name is matched. |  | ||||||
|  | 	err = errNoItems | ||||||
|  | 	if wildcard(r.service) && !wildcard(r.namespace) { | ||||||
|  | 		// If namespace exist, err should be nil, so that we return nodata instead of NXDOMAIN | ||||||
|  | 		if k.namespace(namespace) { | ||||||
|  | 			err = nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		endpointsListFunc func() []*api.Endpoints | 		endpointsListFunc func() []*api.Endpoints | ||||||
| @@ -449,15 +463,6 @@ func wildcard(s string) bool { | |||||||
| 	return s == "*" || s == "any" | 	return s == "*" || s == "any" | ||||||
| } | } | ||||||
|  |  | ||||||
| // namespaceExposed returns true when the namespace is exposed. |  | ||||||
| func (k *Kubernetes) namespaceExposed(namespace string) bool { |  | ||||||
| 	_, ok := k.Namespaces[namespace] |  | ||||||
| 	if len(k.Namespaces) > 0 && !ok { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	// Svc is the DNS schema for kubernetes services | 	// Svc is the DNS schema for kubernetes services | ||||||
| 	Svc = "svc" | 	Svc = "svc" | ||||||
|   | |||||||
| @@ -332,6 +332,14 @@ func (APIConnServiceTest) GetNodeByName(name string) (*api.Node, error) { | |||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (APIConnServiceTest) GetNamespaceByName(name string) (*api.Namespace, error) { | ||||||
|  | 	return &api.Namespace{ | ||||||
|  | 		ObjectMeta: meta.ObjectMeta{ | ||||||
|  | 			Name: name, | ||||||
|  | 		}, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestServices(t *testing.T) { | func TestServices(t *testing.T) { | ||||||
|  |  | ||||||
| 	k := New([]string{"interwebs.test."}) | 	k := New([]string{"interwebs.test."}) | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								plugin/kubernetes/namespace.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								plugin/kubernetes/namespace.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | package kubernetes | ||||||
|  |  | ||||||
|  | // namespace checks if namespace n exists in this cluster. This returns true | ||||||
|  | // even for non exposed namespaces, see namespaceExposed. | ||||||
|  | func (k *Kubernetes) namespace(n string) bool { | ||||||
|  | 	ns, err := k.APIConn.GetNamespaceByName(n) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return ns.ObjectMeta.Name == n | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // namespaceExposed returns true when the namespace is exposed. | ||||||
|  | func (k *Kubernetes) namespaceExposed(namespace string) bool { | ||||||
|  | 	_, ok := k.Namespaces[namespace] | ||||||
|  | 	if len(k.Namespaces) > 0 && !ok { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
| @@ -55,6 +55,9 @@ func (APIConnTest) EpIndexReverse(string) []*api.Endpoints { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (APIConnTest) GetNodeByName(name string) (*api.Node, error) { return &api.Node{}, nil } | func (APIConnTest) GetNodeByName(name string) (*api.Node, error) { return &api.Node{}, nil } | ||||||
|  | func (APIConnTest) GetNamespaceByName(name string) (*api.Namespace, error) { | ||||||
|  | 	return &api.Namespace{}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestNsAddr(t *testing.T) { | func TestNsAddr(t *testing.T) { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -86,6 +86,14 @@ func (APIConnReverseTest) GetNodeByName(name string) (*api.Node, error) { | |||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (APIConnReverseTest) GetNamespaceByName(name string) (*api.Namespace, error) { | ||||||
|  | 	return &api.Namespace{ | ||||||
|  | 		ObjectMeta: meta.ObjectMeta{ | ||||||
|  | 			Name: name, | ||||||
|  | 		}, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestReverse(t *testing.T) { | func TestReverse(t *testing.T) { | ||||||
|  |  | ||||||
| 	k := New([]string{"cluster.local.", "0.10.in-addr.arpa.", "168.192.in-addr.arpa."}) | 	k := New([]string{"cluster.local.", "0.10.in-addr.arpa.", "168.192.in-addr.arpa."}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user