mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	mw/kubernetes: remove federation and cidr (#916)
* mw/kubernetes: remove federation and cidr Remove both as we have a corefile syntax change that handles cidr and remove federation because that is going to be its own middleware. * backwards incompat changes This PR: * removes cidr from kubernetes (core Corefile feature now) * removes federation from kubernets (comes back as new middleware) * [remove autopath - which was already gone, so that already was backwards incompat] * adds `fallthrough` to the *etcd* middleware and makes you enable it. * Fail on unknown properties * documentation * Disable TestHealthCheck as it uses realtime and fails
This commit is contained in:
		| @@ -21,15 +21,14 @@ all the zones the middleware should be authoritative for. | ||||
|  | ||||
| ``` | ||||
| kubernetes [ZONES...] { | ||||
| 	resyncperiod DURATION | ||||
| 	endpoint URL | ||||
| 	tls CERT KEY CACERT | ||||
| 	namespaces NAMESPACE [NAMESPACE...] | ||||
| 	labels EXPRESSION | ||||
| 	pods POD-MODE | ||||
| 	upstream ADDRESS [ADDRESS...] | ||||
| 	federation NAME DOMAIN | ||||
| 	fallthrough | ||||
|     resyncperiod DURATION | ||||
|     endpoint URL | ||||
|     tls CERT KEY CACERT | ||||
|     namespaces NAMESPACE [NAMESPACE...] | ||||
|     labels EXPRESSION | ||||
|     pods POD-MODE | ||||
|     upstream ADDRESS [ADDRESS...] | ||||
|     fallthrough | ||||
| } | ||||
| ``` | ||||
| * `resyncperiod` specifies the Kubernetes data API **DURATION** period. | ||||
| @@ -63,8 +62,6 @@ kubernetes [ZONES...] { | ||||
| * `upstream` **ADDRESS [ADDRESS...]** defines the upstream resolvers used for resolving services | ||||
|   that point to external hosts (External Services).  **ADDRESS** can be an ip, an ip:port, or a path | ||||
|   to a file structured like resolv.conf. | ||||
| * `federation` **NAME DOMAIN** defines federation membership.  One line for each federation | ||||
|   membership. Each line consists of the name of the federation, and the domain. | ||||
| * `fallthrough`  If a query for a record in the cluster zone results in NXDOMAIN, normally that is | ||||
|   what the response will be. However, if you specify this option, the query will instead be passed | ||||
|   on down the middleware chain, which can include another middleware to handle the query. | ||||
| @@ -85,40 +82,47 @@ here: | ||||
|  | ||||
| Or you can selectively expose some namespaces: | ||||
|  | ||||
| 	kubernetes cluster.local { | ||||
| 		namespaces test staging | ||||
|     } | ||||
|  | ||||
| If you want to use federation, just use the `federation` option. Here we handle all service requests | ||||
| in the `prod` and `stage` federations. We resolve upstream records using the servers configured in | ||||
| `/etc/resolv.conf`. | ||||
|  | ||||
|     . { | ||||
|         kubernetes cluster.local { | ||||
| 		    federation prod prod.feddomain.com | ||||
| 		    federation stage stage.feddomain.com | ||||
| 		    upstream /etc/resolv.conf | ||||
|     	} | ||||
|     kubernetes cluster.local { | ||||
|         namespaces test staging | ||||
|     } | ||||
|  | ||||
| And finally we can connect to Kubernetes from outside the cluster: | ||||
|  | ||||
| 	kubernetes cluster.local { | ||||
| 		endpoint https://k8s-endpoint:8443 | ||||
| 		tls cert key cacert | ||||
| 	} | ||||
|     kubernetes cluster.local { | ||||
|         endpoint https://k8s-endpoint:8443 | ||||
|         tls cert key cacert | ||||
|     } | ||||
|  | ||||
| ## Enabling server-side domain search path completion with *autopath* | ||||
| ## AutoPath | ||||
|  | ||||
| The *kubernetes* middleware can be used in conjunction with the *autopath* middleware.  Using this feature enables server-side domain search path completion in kubernetes clusters.  Note: `pods` must be set to `verified` for this to function properly. | ||||
| The *kubernetes* middleware can be used in conjunction with the *autopath* middleware.  Using this | ||||
| feature enables server-side domain search path completion in kubernetes clusters.  Note: `pods` must | ||||
| be set to `verified` for this to function properly. | ||||
|  | ||||
| 	autopath @kubernetes | ||||
| 	kubernetes cluster.local { | ||||
| 		pods verified | ||||
| 	} | ||||
|     cluster.local { | ||||
|         autopath @kubernetes | ||||
|         kubernetes { | ||||
|             pods verified | ||||
|         } | ||||
|     } | ||||
|  | ||||
| ## Federation | ||||
|  | ||||
| The *kubernetes* middleware can be used in conjunction with the *federation* middleware.  Using this | ||||
| feature enables serving federated domains from the kubernetes clusters. | ||||
|  | ||||
|     cluster.local { | ||||
|         federation { | ||||
|             fallthrough | ||||
|             prod prod.example.org | ||||
|             staging staging.example.org | ||||
|  | ||||
|         } | ||||
|         kubernetes | ||||
|     } | ||||
|  | ||||
|  | ||||
| ## Wildcard | ||||
| ## Wildcards | ||||
|  | ||||
| Some query labels accept a wildcard value to match any value.  If a label is a valid wildcard (\*, | ||||
| or the word "any"), then that label will match all values.  The labels that accept wildcards are: | ||||
|   | ||||
| @@ -1,96 +0,0 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/coredns/coredns/middleware/etcd/msg" | ||||
| ) | ||||
|  | ||||
| // Federation holds TODO(...). | ||||
| type Federation struct { | ||||
| 	name string | ||||
| 	zone string | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	// TODO: Do not hardcode these labels. Pull them out of the API instead. | ||||
| 	// | ||||
| 	// We can get them via .... | ||||
| 	//   import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	//     metav1.LabelZoneFailureDomain | ||||
| 	//     metav1.LabelZoneRegion | ||||
| 	// | ||||
| 	// But importing above breaks coredns with flag collision of 'log_dir' | ||||
|  | ||||
| 	labelAvailabilityZone = "failure-domain.beta.kubernetes.io/zone" | ||||
| 	labelRegion           = "failure-domain.beta.kubernetes.io/region" | ||||
| ) | ||||
|  | ||||
| // stripFederation removes the federation segment from the segment list, if it | ||||
| // matches a configured federation name. | ||||
| func (k *Kubernetes) stripFederation(segs []string) (string, []string) { | ||||
|  | ||||
| 	if len(segs) < 3 { | ||||
| 		return "", segs | ||||
| 	} | ||||
| 	for _, f := range k.Federations { | ||||
| 		if f.name == segs[len(segs)-2] { | ||||
| 			fed := segs[len(segs)-2] | ||||
| 			segs[len(segs)-2] = segs[len(segs)-1] | ||||
| 			segs = segs[:len(segs)-1] | ||||
| 			return fed, segs | ||||
| 		} | ||||
| 	} | ||||
| 	return "", segs | ||||
| } | ||||
|  | ||||
| // federationCNAMERecord returns a service record for the requested federated service | ||||
| // with the target host in the federated CNAME format which the external DNS provider | ||||
| // should be able to resolve | ||||
| func (k *Kubernetes) federationCNAMERecord(r recordRequest) msg.Service { | ||||
|  | ||||
| 	myNodeName := k.localNodeName() | ||||
| 	node, err := k.APIConn.GetNodeByName(myNodeName) | ||||
| 	if err != nil { | ||||
| 		return msg.Service{} | ||||
| 	} | ||||
|  | ||||
| 	for _, f := range k.Federations { | ||||
| 		if f.name != r.federation { | ||||
| 			continue | ||||
| 		} | ||||
| 		if r.endpoint == "" { | ||||
| 			return msg.Service{ | ||||
| 				Key:  strings.Join([]string{msg.Path(r.zone, "coredns"), r.podOrSvc, r.federation, r.namespace, r.service}, "/"), | ||||
| 				Host: strings.Join([]string{r.service, r.namespace, r.federation, r.podOrSvc, node.Labels[labelAvailabilityZone], node.Labels[labelRegion], f.zone}, "."), | ||||
| 			} | ||||
| 		} | ||||
| 		return msg.Service{ | ||||
| 			Key:  strings.Join([]string{msg.Path(r.zone, "coredns"), r.podOrSvc, r.federation, r.namespace, r.service, r.endpoint}, "/"), | ||||
| 			Host: strings.Join([]string{r.endpoint, r.service, r.namespace, r.federation, r.podOrSvc, node.Labels[labelAvailabilityZone], node.Labels[labelRegion], f.zone}, "."), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return msg.Service{} | ||||
| } | ||||
|  | ||||
| func (k *Kubernetes) localNodeName() string { | ||||
| 	localIP := k.interfaceAddrsFunc() | ||||
| 	if localIP == nil { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// Find endpoint matching localIP | ||||
| 	endpointsList := k.APIConn.EndpointsList() | ||||
| 	for _, ep := range endpointsList.Items { | ||||
| 		for _, eps := range ep.Subsets { | ||||
| 			for _, addr := range eps.Addresses { | ||||
| 				if localIP.Equal(net.ParseIP(addr.IP)) { | ||||
| 					return *addr.NodeName | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| @@ -1,108 +0,0 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/coredns/coredns/middleware/etcd/msg" | ||||
| 	"github.com/coredns/coredns/request" | ||||
| 	"github.com/miekg/dns" | ||||
| 	"k8s.io/client-go/1.5/pkg/api" | ||||
| ) | ||||
|  | ||||
| func testStripFederation(t *testing.T, k Kubernetes, input []string, expectedFed string, expectedSegs string) { | ||||
| 	fed, segs := k.stripFederation(input) | ||||
|  | ||||
| 	if expectedSegs != strings.Join(segs, ".") { | ||||
| 		t.Errorf("For '%v', expected segs result '%v'. Instead got result '%v'.", strings.Join(input, "."), expectedSegs, strings.Join(segs, ".")) | ||||
| 	} | ||||
| 	if expectedFed != fed { | ||||
| 		t.Errorf("For '%v', expected fed result '%v'. Instead got result '%v'.", strings.Join(input, "."), expectedFed, fed) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestStripFederation(t *testing.T) { | ||||
| 	k := Kubernetes{Zones: []string{"inter.webs.test"}} | ||||
| 	k.Federations = []Federation{{name: "fed", zone: "era.tion.com"}} | ||||
|  | ||||
| 	testStripFederation(t, k, []string{"service", "ns", "fed", Svc}, "fed", "service.ns.svc") | ||||
| 	testStripFederation(t, k, []string{"service", "ns", "foo", Svc}, "", "service.ns.foo.svc") | ||||
| 	testStripFederation(t, k, []string{"foo", "bar"}, "", "foo.bar") | ||||
|  | ||||
| } | ||||
|  | ||||
| type apiConnFedTest struct{} | ||||
|  | ||||
| func (apiConnFedTest) Run()                          { return } | ||||
| func (apiConnFedTest) Stop() error                   { return nil } | ||||
| func (apiConnFedTest) ServiceList() []*api.Service   { return []*api.Service{} } | ||||
| func (apiConnFedTest) PodIndex(string) []interface{} { return nil } | ||||
|  | ||||
| func (apiConnFedTest) EndpointsList() api.EndpointsList { | ||||
| 	n := "test.node.foo.bar" | ||||
| 	return api.EndpointsList{ | ||||
| 		Items: []api.Endpoints{ | ||||
| 			{ | ||||
| 				Subsets: []api.EndpointSubset{ | ||||
| 					{ | ||||
| 						Addresses: []api.EndpointAddress{ | ||||
| 							{ | ||||
| 								IP:       "10.9.8.7", | ||||
| 								NodeName: &n, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (apiConnFedTest) GetNodeByName(name string) (api.Node, error) { | ||||
| 	if name != "test.node.foo.bar" { | ||||
| 		return api.Node{}, nil | ||||
| 	} | ||||
| 	return api.Node{ | ||||
| 		ObjectMeta: api.ObjectMeta{ | ||||
| 			Name: "test.node.foo.bar", | ||||
| 			Labels: map[string]string{ | ||||
| 				labelRegion:           "fd-r", | ||||
| 				labelAvailabilityZone: "fd-az", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func testFederationCNAMERecord(t *testing.T, k Kubernetes, input recordRequest, expected msg.Service) { | ||||
| 	svc := k.federationCNAMERecord(input) | ||||
|  | ||||
| 	if expected.Host != svc.Host { | ||||
| 		t.Errorf("For '%v', expected Host result '%v'. Instead got result '%v'.", input, expected.Host, svc.Host) | ||||
| 	} | ||||
| 	if expected.Key != svc.Key { | ||||
| 		t.Errorf("For '%v', expected Key result '%v'. Instead got result '%v'.", input, expected.Key, svc.Key) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestFederationCNAMERecord(t *testing.T) { | ||||
| 	k := Kubernetes{Zones: []string{"inter.webs."}} | ||||
| 	k.Federations = []Federation{{name: "fed", zone: "era.tion.com"}} | ||||
| 	k.APIConn = apiConnFedTest{} | ||||
| 	k.interfaceAddrsFunc = func() net.IP { return net.ParseIP("10.9.8.7") } | ||||
|  | ||||
| 	m := new(dns.Msg) | ||||
| 	state := request.Request{Zone: "inter.webs.", Req: m} | ||||
|  | ||||
| 	m.SetQuestion("s1.ns.fed.svc.inter.webs.", dns.TypeA) | ||||
| 	r, _ := k.parseRequest(state) | ||||
| 	testFederationCNAMERecord(t, k, r, msg.Service{Key: "/coredns/webs/inter/svc/fed/ns/s1", Host: "s1.ns.fed.svc.fd-az.fd-r.era.tion.com"}) | ||||
|  | ||||
| 	m.SetQuestion("ep1.s1.ns.fed.svc.inter.webs.", dns.TypeA) | ||||
| 	r, _ = k.parseRequest(state) | ||||
| 	testFederationCNAMERecord(t, k, r, msg.Service{Key: "/coredns/webs/inter/svc/fed/ns/s1/ep1", Host: "ep1.s1.ns.fed.svc.fd-az.fd-r.era.tion.com"}) | ||||
|  | ||||
| 	m.SetQuestion("ep1.s1.ns.foo.svc.inter.webs.", dns.TypeA) | ||||
| 	r, _ = k.parseRequest(state) | ||||
| 	testFederationCNAMERecord(t, k, r, msg.Service{Key: "", Host: ""}) | ||||
| } | ||||
| @@ -25,18 +25,10 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M | ||||
| 	// otherwise delegate to the next in the pipeline. | ||||
| 	zone := middleware.Zones(k.Zones).Matches(state.Name()) | ||||
| 	if zone == "" { | ||||
| 		if state.QType() != dns.TypePTR { | ||||
| 		if k.Fallthrough { | ||||
| 			return middleware.NextOrFailure(k.Name(), k.Next, ctx, w, r) | ||||
| 		} | ||||
| 		// If this is a PTR request, and the request is in a defined | ||||
| 		// pod/service cidr range, process the request in this middleware, | ||||
| 		// otherwise pass to next middleware. | ||||
| 		if !k.isRequestInReverseRange(state.Name()) { | ||||
| 			return middleware.NextOrFailure(k.Name(), k.Next, ctx, w, r) | ||||
| 		} | ||||
|  | ||||
| 		// Set the zone to this specific request, as we want to handle this reverse request. | ||||
| 		zone = state.Name() | ||||
| 		return dns.RcodeServerFailure, nil | ||||
| 	} | ||||
|  | ||||
| 	state.Zone = zone | ||||
|   | ||||
| @@ -59,28 +59,6 @@ var dnsTestCases = map[string](*test.Case){ | ||||
| 			test.CNAME("external.testns.svc.cluster.local.	0	IN	CNAME	ext.interwebs.test."), | ||||
| 		}, | ||||
| 	}, | ||||
| 	"A Service (Local Federated)": { | ||||
| 		Qname: "svc1.testns.fed.svc.cluster.local.", Qtype: dns.TypeA, | ||||
| 		Rcode: dns.RcodeSuccess, | ||||
| 		Answer: []dns.RR{ | ||||
| 			test.A("svc1.testns.fed.svc.cluster.local.	0	IN	A	10.0.0.1"), | ||||
| 		}, | ||||
| 	}, | ||||
| 	"PTR Service": { | ||||
| 		Qname: "1.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR, | ||||
| 		Rcode: dns.RcodeSuccess, | ||||
| 		Answer: []dns.RR{ | ||||
| 			test.PTR("1.0.0.10.in-addr.arpa.	0	IN	PTR	svc1.testns.svc.cluster.local."), | ||||
| 		}, | ||||
| 	}, | ||||
| 	// TODO A Service (Remote Federated) | ||||
| 	"CNAME Service (Remote Federated)": { | ||||
| 		Qname: "svc0.testns.fed.svc.cluster.local.", Qtype: dns.TypeCNAME, | ||||
| 		Rcode: dns.RcodeSuccess, | ||||
| 		Answer: []dns.RR{ | ||||
| 			test.CNAME("svc0.testns.fed.svc.cluster.local.	0	IN	CNAME	svc0.testns.fed.svc.fd-az.fd-r.federal.test."), | ||||
| 		}, | ||||
| 	}, | ||||
| 	"AAAA Service (existing service)": { | ||||
| 		Qname: "svc1.testns.svc.cluster.local.", Qtype: dns.TypeAAAA, | ||||
| 		Rcode:  dns.RcodeSuccess, | ||||
| @@ -174,7 +152,6 @@ func TestServeDNS(t *testing.T) { | ||||
| 	_, cidr, _ := net.ParseCIDR("10.0.0.0/8") | ||||
|  | ||||
| 	k.ReverseCidrs = []net.IPNet{*cidr} | ||||
| 	k.Federations = []Federation{{name: "fed", zone: "federal.test."}} | ||||
| 	k.APIConn = &APIConnServeTest{} | ||||
| 	k.interfaceAddrsFunc = localPodIP | ||||
| 	k.Next = test.NextHandler(dns.RcodeSuccess, nil) | ||||
| @@ -405,10 +382,6 @@ func (APIConnServeTest) GetNodeByName(name string) (api.Node, error) { | ||||
| 	return api.Node{ | ||||
| 		ObjectMeta: api.ObjectMeta{ | ||||
| 			Name: "test.node.foo.bar", | ||||
| 			Labels: map[string]string{ | ||||
| 				labelRegion:           "fd-r", | ||||
| 				labelAvailabilityZone: "fd-az", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|   | ||||
| @@ -41,7 +41,6 @@ type Kubernetes struct { | ||||
| 	APIConn       dnsController | ||||
| 	ResyncPeriod  time.Duration | ||||
| 	Namespaces    []string | ||||
| 	Federations   []Federation | ||||
| 	LabelSelector *unversionedapi.LabelSelector | ||||
| 	Selector      *labels.Selector | ||||
| 	PodMode       string | ||||
| @@ -309,13 +308,6 @@ func (k *Kubernetes) Entries(r recordRequest) ([]msg.Service, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(services) == 0 && len(pods) == 0 { | ||||
| 		// Did not find item in k8s, try federated | ||||
| 		if r.federation != "" { | ||||
| 			fedCNAME := k.federationCNAMERecord(r) | ||||
| 			if fedCNAME.Key != "" { | ||||
| 				return []msg.Service{fedCNAME}, nil | ||||
| 			} | ||||
| 		} | ||||
| 		return nil, errNoItems | ||||
| 	} | ||||
|  | ||||
| @@ -344,15 +336,9 @@ func (k *Kubernetes) getRecordsForK8sItems(services []kService, pods []kPod, r r | ||||
| 		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), | ||||
| 				} | ||||
| 				if r.federation != "" { | ||||
| 					s.Key = strings.Join([]string{zonePath, Svc, r.federation, svc.namespace, svc.name, endpointHostname(ep.addr)}, "/") | ||||
| 				} else { | ||||
| 					s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name, endpointHostname(ep.addr)}, "/") | ||||
| 				} | ||||
| 				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 | ||||
| @@ -360,37 +346,22 @@ func (k *Kubernetes) getRecordsForK8sItems(services []kService, pods []kPod, r r | ||||
|  | ||||
| 		// Create records for each exposed port... | ||||
| 		for _, p := range svc.ports { | ||||
| 			s := msg.Service{ | ||||
| 				Host: svc.addr, | ||||
| 				Port: int(p.Port)} | ||||
|  | ||||
| 			if r.federation != "" { | ||||
| 				s.Key = strings.Join([]string{zonePath, Svc, r.federation, svc.namespace, svc.name}, "/") | ||||
| 			} else { | ||||
| 				s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/") | ||||
| 			} | ||||
| 			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} | ||||
| 		s := msg.Service{Key: strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/"), Host: svc.addr} | ||||
| 		if t, _ := s.HostType(); t == dns.TypeCNAME { | ||||
| 			if r.federation != "" { | ||||
| 				s.Key = strings.Join([]string{zonePath, Svc, r.federation, svc.namespace, svc.name}, "/") | ||||
| 			} else { | ||||
| 				s.Key = strings.Join([]string{zonePath, Svc, svc.namespace, svc.name}, "/") | ||||
| 			} | ||||
| 			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, | ||||
| 		} | ||||
| 		s := msg.Service{Key: strings.Join([]string{zonePath, Pod, p.namespace, p.name}, "/"), Host: p.addr} | ||||
| 		records = append(records, s) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -189,10 +189,6 @@ func (APIConnServiceTest) GetNodeByName(name string) (api.Node, error) { | ||||
| 	return api.Node{ | ||||
| 		ObjectMeta: api.ObjectMeta{ | ||||
| 			Name: "test.node.foo.bar", | ||||
| 			Labels: map[string]string{ | ||||
| 				labelRegion:           "fd-r", | ||||
| 				labelAvailabilityZone: "fd-az", | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| @@ -200,7 +196,6 @@ func (APIConnServiceTest) GetNodeByName(name string) (api.Node, error) { | ||||
| func TestServices(t *testing.T) { | ||||
|  | ||||
| 	k := Kubernetes{Zones: []string{"interwebs.test."}} | ||||
| 	k.Federations = []Federation{{name: "fed", zone: "era.tion.com"}} | ||||
| 	k.interfaceAddrsFunc = localPodIP | ||||
| 	k.APIConn = &APIConnServiceTest{} | ||||
|  | ||||
| @@ -221,10 +216,6 @@ func TestServices(t *testing.T) { | ||||
|  | ||||
| 		// External Services | ||||
| 		{qname: "external.testns.svc.interwebs.test.", qtype: dns.TypeCNAME, answer: svcAns{host: "coredns.io", key: "/coredns/test/interwebs/svc/testns/external"}}, | ||||
|  | ||||
| 		// Federated Services | ||||
| 		{qname: "svc1.testns.fed.svc.interwebs.test.", qtype: dns.TypeA, answer: svcAns{host: "10.0.0.1", key: "/coredns/test/interwebs/svc/fed/testns/svc1"}}, | ||||
| 		{qname: "svc0.testns.fed.svc.interwebs.test.", qtype: dns.TypeA, answer: svcAns{host: "svc0.testns.fed.svc.fd-az.fd-r.era.tion.com", key: "/coredns/test/interwebs/svc/fed/testns/svc0"}}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range tests { | ||||
|   | ||||
| @@ -19,14 +19,13 @@ type recordRequest struct { | ||||
| 	namespace string | ||||
| 	// A each name can be for a pod or a service, here we track what we've seen. This value is true for | ||||
| 	// pods and false for services. If we ever need to extend this well use a typed value. | ||||
| 	podOrSvc   string | ||||
| 	zone       string | ||||
| 	federation string | ||||
| 	podOrSvc string | ||||
| 	zone     string | ||||
| } | ||||
|  | ||||
| // parseRequest parses the qname to find all the elements we need for querying k8s. | ||||
| func (k *Kubernetes) parseRequest(state request.Request) (r recordRequest, err error) { | ||||
| 	// 3 Possible cases | ||||
| 	// 3 Possible cases: TODO(chris): remove federations comments here. | ||||
| 	//   SRV Request: _port._protocol.service.namespace.[federation.]type.zone | ||||
| 	//   A Request (endpoint): endpoint.service.namespace.[federation.]type.zone | ||||
| 	//   A Request (service): service.namespace.[federation.]type.zone | ||||
| @@ -35,7 +34,6 @@ func (k *Kubernetes) parseRequest(state request.Request) (r recordRequest, err e | ||||
| 	segs := dns.SplitDomainName(base) | ||||
|  | ||||
| 	r.zone = state.Zone | ||||
| 	r.federation, segs = k.stripFederation(segs) | ||||
|  | ||||
| 	if state.QType() == dns.TypeNS { | ||||
| 		return r, nil | ||||
| @@ -112,6 +110,5 @@ func (r recordRequest) String() string { | ||||
| 	s += "." + r.namespace | ||||
| 	s += "." + r.podOrSvc | ||||
| 	s += "." + r.zone | ||||
| 	s += "." + r.federation | ||||
| 	return s | ||||
| } | ||||
|   | ||||
| @@ -18,21 +18,21 @@ func TestParseRequest(t *testing.T) { | ||||
| 		{ | ||||
| 			// valid SRV request | ||||
| 			"_http._tcp.webs.mynamespace.svc.inter.webs.test.", dns.TypeSRV, | ||||
| 			"http.tcp..webs.mynamespace.svc.intern.webs.tests..", | ||||
| 			"http.tcp..webs.mynamespace.svc.intern.webs.tests.", | ||||
| 		}, | ||||
| 		{ | ||||
| 			// wildcard acceptance | ||||
| 			"*.any.*.any.svc.inter.webs.test.", dns.TypeSRV, | ||||
| 			"*.any..*.any.svc.intern.webs.tests..", | ||||
| 			"*.any..*.any.svc.intern.webs.tests.", | ||||
| 		}, | ||||
| 		{ | ||||
| 			// A request of endpoint | ||||
| 			"1-2-3-4.webs.mynamespace.svc.inter.webs.test.", dns.TypeA, | ||||
| 			"..1-2-3-4.webs.mynamespace.svc.intern.webs.tests..", | ||||
| 			"..1-2-3-4.webs.mynamespace.svc.intern.webs.tests.", | ||||
| 		}, | ||||
| 		{ | ||||
| 			"inter.webs.test.", dns.TypeNS, | ||||
| 			"......intern.webs.tests..", | ||||
| 			"......intern.webs.tests.", | ||||
| 		}, | ||||
| 	} | ||||
| 	for i, tc := range tests { | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
|  | ||||
| 	"github.com/coredns/coredns/middleware" | ||||
| 	"github.com/coredns/coredns/middleware/etcd/msg" | ||||
| 	"github.com/coredns/coredns/middleware/pkg/dnsutil" | ||||
| @@ -20,13 +18,3 @@ func (k *Kubernetes) Reverse(state request.Request, exact bool, opt middleware.O | ||||
| 	records := k.getServiceRecordForIP(ip, state.Name()) | ||||
| 	return records, nil, nil | ||||
| } | ||||
|  | ||||
| func (k *Kubernetes) isRequestInReverseRange(name string) bool { | ||||
| 	ip := dnsutil.ExtractAddressFromReverse(name) | ||||
| 	for _, c := range k.ReverseCidrs { | ||||
| 		if c.Contains(net.ParseIP(ip)) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
| @@ -1,33 +0,0 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestIsRequestInReverseRange(t *testing.T) { | ||||
|  | ||||
| 	tests := []struct { | ||||
| 		cidr     string | ||||
| 		name     string | ||||
| 		expected bool | ||||
| 	}{ | ||||
| 		{"1.2.3.0/24", "4.3.2.1.in-addr.arpa.", true}, | ||||
| 		{"1.2.3.0/24", "5.3.2.1.in-addr.arpa.", true}, | ||||
| 		{"5.6.0.0/16", "5.4.6.5.in-addr.arpa.", true}, | ||||
| 		{"1.2.3.0/24", "5.4.2.1.in-addr.arpa.", false}, | ||||
| 		{"5.6.0.0/16", "5.4.2.1.in-addr.arpa.", false}, | ||||
| 		{"5.6.0.0/16", "5.6.0.1.in-addr.arpa.", false}, | ||||
| 	} | ||||
|  | ||||
| 	k := Kubernetes{} | ||||
|  | ||||
| 	for _, test := range tests { | ||||
| 		_, cidr, _ := net.ParseCIDR(test.cidr) | ||||
| 		k.ReverseCidrs = []net.IPNet{*cidr} | ||||
| 		result := k.isRequestInReverseRange(test.name) | ||||
| 		if result != test.expected { | ||||
| 			t.Errorf("Expected '%v' for '%v' in %v.", test.expected, test.name, test.cidr) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -3,8 +3,6 @@ package kubernetes | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| @@ -74,141 +72,113 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) { | ||||
| 	k8s.autoPathSearch = searchFromResolvConf() | ||||
|  | ||||
| 	for c.Next() { | ||||
| 		if c.Val() == "kubernetes" { | ||||
| 			zones := c.RemainingArgs() | ||||
| 		zones := c.RemainingArgs() | ||||
|  | ||||
| 			if len(zones) != 0 { | ||||
| 				k8s.Zones = zones | ||||
| 				middleware.Zones(k8s.Zones).Normalize() | ||||
| 			} else { | ||||
| 				k8s.Zones = make([]string, len(c.ServerBlockKeys)) | ||||
| 				for i := 0; i < len(c.ServerBlockKeys); i++ { | ||||
| 					k8s.Zones[i] = middleware.Host(c.ServerBlockKeys[i]).Normalize() | ||||
| 				} | ||||
| 		if len(zones) != 0 { | ||||
| 			k8s.Zones = zones | ||||
| 			middleware.Zones(k8s.Zones).Normalize() | ||||
| 		} else { | ||||
| 			k8s.Zones = make([]string, len(c.ServerBlockKeys)) | ||||
| 			for i := 0; i < len(c.ServerBlockKeys); i++ { | ||||
| 				k8s.Zones[i] = middleware.Host(c.ServerBlockKeys[i]).Normalize() | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 			k8s.primaryZoneIndex = -1 | ||||
| 			for i, z := range k8s.Zones { | ||||
| 				if strings.HasSuffix(z, "in-addr.arpa.") || strings.HasSuffix(z, "ip6.arpa.") { | ||||
| 		k8s.primaryZoneIndex = -1 | ||||
| 		for i, z := range k8s.Zones { | ||||
| 			if strings.HasSuffix(z, "in-addr.arpa.") || strings.HasSuffix(z, "ip6.arpa.") { | ||||
| 				continue | ||||
| 			} | ||||
| 			k8s.primaryZoneIndex = i | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if k8s.primaryZoneIndex == -1 { | ||||
| 			return nil, errors.New("non-reverse zone name must be used") | ||||
| 		} | ||||
|  | ||||
| 		for c.NextBlock() { | ||||
| 			switch c.Val() { | ||||
| 			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 | ||||
| 				} | ||||
| 				k8s.primaryZoneIndex = i | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			if k8s.primaryZoneIndex == -1 { | ||||
| 				return nil, errors.New("non-reverse zone name must be given for Kubernetes") | ||||
| 			} | ||||
|  | ||||
| 			for c.NextBlock() { | ||||
| 				switch c.Val() { | ||||
| 				case "cidrs": | ||||
|  | ||||
| 					// DEPRECATION WARNING | ||||
| 					log.Printf("[WARNING] \"cidrs\" will be removed for CoreDNS soon. See https://coredns.io/2017/07/23/corefile-explained#reverse-zones for the replacement") | ||||
|  | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) > 0 { | ||||
| 						for _, cidrStr := range args { | ||||
| 							_, cidr, err := net.ParseCIDR(cidrStr) | ||||
| 							if err != nil { | ||||
| 								return nil, fmt.Errorf("invalid cidr: %s", cidrStr) | ||||
| 							} | ||||
| 							k8s.ReverseCidrs = append(k8s.ReverseCidrs, *cidr) | ||||
|  | ||||
| 						} | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, c.ArgErr() | ||||
| 				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 { | ||||
| 						k8s.Namespaces = append(k8s.Namespaces, args...) | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, c.ArgErr() | ||||
| 				case "endpoint": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) > 0 { | ||||
| 						for _, endpoint := range strings.Split(args[0], ",") { | ||||
| 							k8s.APIServerList = append(k8s.APIServerList, strings.TrimSpace(endpoint)) | ||||
| 						} | ||||
| 						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 "resyncperiod": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) > 0 { | ||||
| 						rp, err := time.ParseDuration(args[0]) | ||||
| 						if err != nil { | ||||
| 							return nil, fmt.Errorf("unable to parse resync duration value: '%v': %v", args[0], err) | ||||
| 						} | ||||
| 						k8s.ResyncPeriod = rp | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, c.ArgErr() | ||||
| 				case "labels": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) > 0 { | ||||
| 						labelSelectorString := strings.Join(args, " ") | ||||
| 						ls, err := unversionedapi.ParseToLabelSelector(labelSelectorString) | ||||
| 						if err != nil { | ||||
| 							return nil, fmt.Errorf("unable to parse label selector value: '%v': %v", labelSelectorString, err) | ||||
| 						} | ||||
| 						k8s.LabelSelector = ls | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, c.ArgErr() | ||||
| 				case "fallthrough": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) == 0 { | ||||
| 						k8s.Fallthrough = true | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, c.ArgErr() | ||||
| 				case "upstream": | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) == 0 { | ||||
| 						return nil, c.ArgErr() | ||||
| 					} | ||||
| 					ups, err := dnsutil.ParseHostPortOrFile(args...) | ||||
| 					if err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					k8s.Proxy = proxy.NewLookup(ups) | ||||
| 				case "federation": // name zone | ||||
| 					args := c.RemainingArgs() | ||||
| 					if len(args) == 2 { | ||||
| 						k8s.Federations = append(k8s.Federations, Federation{ | ||||
| 							name: args[0], | ||||
| 							zone: args[1], | ||||
| 						}) | ||||
| 						continue | ||||
| 					} | ||||
| 					return nil, fmt.Errorf("incorrect number of arguments for federation, got %v, expected 2", len(args)) | ||||
| 				return nil, c.ArgErr() | ||||
| 			case "namespaces": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) > 0 { | ||||
| 					k8s.Namespaces = append(k8s.Namespaces, args...) | ||||
| 					continue | ||||
| 				} | ||||
| 				return nil, c.ArgErr() | ||||
| 			case "endpoint": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) > 0 { | ||||
| 					for _, endpoint := range strings.Split(args[0], ",") { | ||||
| 						k8s.APIServerList = append(k8s.APIServerList, strings.TrimSpace(endpoint)) | ||||
| 					} | ||||
| 					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 "resyncperiod": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) > 0 { | ||||
| 					rp, err := time.ParseDuration(args[0]) | ||||
| 					if err != nil { | ||||
| 						return nil, fmt.Errorf("unable to parse resync duration value: '%v': %v", args[0], err) | ||||
| 					} | ||||
| 					k8s.ResyncPeriod = rp | ||||
| 					continue | ||||
| 				} | ||||
| 				return nil, c.ArgErr() | ||||
| 			case "labels": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) > 0 { | ||||
| 					labelSelectorString := strings.Join(args, " ") | ||||
| 					ls, err := unversionedapi.ParseToLabelSelector(labelSelectorString) | ||||
| 					if err != nil { | ||||
| 						return nil, fmt.Errorf("unable to parse label selector value: '%v': %v", labelSelectorString, err) | ||||
| 					} | ||||
| 					k8s.LabelSelector = ls | ||||
| 					continue | ||||
| 				} | ||||
| 				return nil, c.ArgErr() | ||||
| 			case "fallthrough": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) == 0 { | ||||
| 					k8s.Fallthrough = true | ||||
| 					continue | ||||
| 				} | ||||
| 				return nil, c.ArgErr() | ||||
| 			case "upstream": | ||||
| 				args := c.RemainingArgs() | ||||
| 				if len(args) == 0 { | ||||
| 					return nil, c.ArgErr() | ||||
| 				} | ||||
| 				ups, err := dnsutil.ParseHostPortOrFile(args...) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				k8s.Proxy = proxy.NewLookup(ups) | ||||
| 			default: | ||||
| 				return nil, c.Errf("unknown property '%s'", c.Val()) | ||||
| 			} | ||||
| 			return k8s, nil | ||||
| 		} | ||||
| 		return k8s, nil | ||||
| 	} | ||||
| 	return nil, errors.New("kubernetes setup called without keyword 'kubernetes' in Corefile") | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,14 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/mholt/caddy" | ||||
| 	unversionedapi "k8s.io/client-go/1.5/pkg/api/unversioned" | ||||
| 	"k8s.io/client-go/1.5/pkg/api/unversioned" | ||||
| ) | ||||
|  | ||||
| func parseCidr(cidr string) net.IPNet { | ||||
| 	_, ipnet, _ := net.ParseCIDR(cidr) | ||||
| 	return *ipnet | ||||
| } | ||||
|  | ||||
| func TestKubernetesParse(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		input                 string        // Corefile data as string | ||||
| @@ -25,7 +19,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 		expectedResyncPeriod  time.Duration // expected resync period value | ||||
| 		expectedLabelSelector string        // expected label selector value | ||||
| 		expectedPodMode       string | ||||
| 		expectedCidrs         []net.IPNet | ||||
| 		expectedFallthrough   bool | ||||
| 		expectedUpstreams     []string | ||||
| 	}{ | ||||
| @@ -39,7 +32,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -52,7 +44,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -66,7 +57,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -81,7 +71,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -96,7 +85,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -111,7 +99,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -126,7 +113,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			30 * time.Second, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -141,7 +127,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			15 * time.Minute, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -156,7 +141,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"environment=prod", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -171,7 +155,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"application=nginx,environment in (production,qa,staging)", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -190,7 +173,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			15 * time.Minute, | ||||
| 			"application=nginx,environment in (production,qa,staging)", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			true, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -204,7 +186,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -219,7 +200,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -234,7 +214,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -249,7 +228,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			0 * time.Minute, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -264,7 +242,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			0 * time.Second, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -279,7 +256,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			0 * time.Second, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -294,7 +270,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			0 * time.Second, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -309,7 +284,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			0 * time.Second, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -325,7 +299,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -341,7 +314,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeInsecure, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -357,7 +329,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeVerified, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -373,39 +344,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeVerified, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| 		// cidrs ok | ||||
| 		{ | ||||
| 			`kubernetes coredns.local { | ||||
| 	cidrs 10.0.0.0/24 10.0.1.0/24 | ||||
| }`, | ||||
| 			false, | ||||
| 			"", | ||||
| 			1, | ||||
| 			0, | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			[]net.IPNet{parseCidr("10.0.0.0/24"), parseCidr("10.0.1.0/24")}, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| 		// cidrs ok | ||||
| 		{ | ||||
| 			`kubernetes coredns.local { | ||||
| 	cidrs hard dry | ||||
| }`, | ||||
| 			true, | ||||
| 			"invalid cidr: hard", | ||||
| 			-1, | ||||
| 			0, | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -421,7 +359,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -437,7 +374,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			[]string{"13.14.15.16:53"}, | ||||
| 		}, | ||||
| @@ -453,7 +389,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			defaultResyncPeriod, | ||||
| 			"", | ||||
| 			PodModeDisabled, | ||||
| 			nil, | ||||
| 			false, | ||||
| 			nil, | ||||
| 		}, | ||||
| @@ -508,7 +443,7 @@ func TestKubernetesParse(t *testing.T) { | ||||
|  | ||||
| 		//    Labels | ||||
| 		if k8sController.LabelSelector != nil { | ||||
| 			foundLabelSelectorString := unversionedapi.FormatLabelSelector(k8sController.LabelSelector) | ||||
| 			foundLabelSelectorString := unversioned.FormatLabelSelector(k8sController.LabelSelector) | ||||
| 			if foundLabelSelectorString != test.expectedLabelSelector { | ||||
| 				t.Errorf("Test %d: Expected kubernetes controller to be initialized with label selector '%s'. Instead found selector '%s' for input '%s'", i, test.expectedLabelSelector, foundLabelSelectorString, test.input) | ||||
| 			} | ||||
| @@ -519,16 +454,6 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 			t.Errorf("Test %d: Expected kubernetes controller to be initialized with pod mode '%s'. Instead found pod mode '%s' for input '%s'", i, test.expectedPodMode, foundPodMode, test.input) | ||||
| 		} | ||||
|  | ||||
| 		//    Cidrs | ||||
| 		foundCidrs := k8sController.ReverseCidrs | ||||
| 		if len(foundCidrs) != len(test.expectedCidrs) { | ||||
| 			t.Errorf("Test %d: Expected kubernetes controller to be initialized with %d cidrs. Instead found %d cidrs for input '%s'", i, len(test.expectedCidrs), len(foundCidrs), test.input) | ||||
| 		} | ||||
| 		for j, cidr := range test.expectedCidrs { | ||||
| 			if cidr.String() != foundCidrs[j].String() { | ||||
| 				t.Errorf("Test %d: Expected kubernetes controller to be initialized with cidr '%s'. Instead found cidr '%s' for input '%s'", i, test.expectedCidrs[j].String(), foundCidrs[j].String(), test.input) | ||||
| 			} | ||||
| 		} | ||||
| 		// fallthrough | ||||
| 		foundFallthrough := k8sController.Fallthrough | ||||
| 		if foundFallthrough != test.expectedFallthrough { | ||||
| @@ -558,70 +483,3 @@ func TestKubernetesParse(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestKubernetesParseFederation(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		input               string // Corefile data as string | ||||
| 		shouldErr           bool   // true if test case is exected to produce an error. | ||||
| 		expectedErrContent  string // substring from the expected error. Empty for positive cases. | ||||
| 		expectedFederations []Federation | ||||
| 	}{ | ||||
| 		// Valid federations | ||||
| 		{ | ||||
| 			`kubernetes coredns.local { | ||||
| 	federation foo bar.crawl.com | ||||
| 	federation fed era.tion.com | ||||
| }`, | ||||
| 			false, | ||||
| 			"", | ||||
| 			[]Federation{ | ||||
| 				{name: "foo", zone: "bar.crawl.com"}, | ||||
| 				{name: "fed", zone: "era.tion.com"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		// Invalid federations | ||||
| 		{ | ||||
| 			`kubernetes coredns.local { | ||||
| 	federation starship | ||||
| }`, | ||||
| 			true, | ||||
| 			`incorrect number of arguments for federation`, | ||||
| 			[]Federation{}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, test := range tests { | ||||
| 		c := caddy.NewTestController("dns", test.input) | ||||
| 		k8sController, err := kubernetesParse(c) | ||||
|  | ||||
| 		if test.shouldErr && err == nil { | ||||
| 			t.Errorf("Test %d: Expected error, but did not find error for input '%s'. Error was: '%v'", i, test.input, err) | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			if !test.shouldErr { | ||||
| 				t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			if test.shouldErr && (len(test.expectedErrContent) < 1) { | ||||
| 				t.Fatalf("Test %d: Test marked as expecting an error, but no expectedErrContent provided for input '%s'. Error was: '%v'", i, test.input, err) | ||||
| 			} | ||||
|  | ||||
| 			if !strings.Contains(err.Error(), test.expectedErrContent) { | ||||
| 				t.Errorf("Test %d: Expected error to contain: %v, found error: %v, input: %s", i, test.expectedErrContent, err, test.input) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		foundFed := k8sController.Federations | ||||
| 		if len(foundFed) != len(test.expectedFederations) { | ||||
| 			t.Errorf("Test %d: Expected kubernetes controller to be initialized with %d fedrations. Instead found %d fedrations for input '%s'", i, len(test.expectedFederations), len(foundFed), test.input) | ||||
| 		} | ||||
| 		for j, fed := range test.expectedFederations { | ||||
| 			if fed != foundFed[j] { | ||||
| 				t.Errorf("Test %d: Expected kubernetes controller to be initialized with federation '%s'. Instead found federation '%s' for input '%s'", i, test.expectedFederations[j], foundFed[j], test.input) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user