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:
parent
818d2b10ad
commit
00f5c7797e
26 changed files with 197 additions and 815 deletions
|
@ -104,6 +104,8 @@ func parseErratic(c *caddy.Controller) (*Erratic, error) {
|
|||
return nil, fmt.Errorf("illegal amount value given %q", args[0])
|
||||
}
|
||||
e.truncate = uint64(amount)
|
||||
default:
|
||||
return nil, c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ If you want to `round robin` A and AAAA responses look at the `loadbalance` midd
|
|||
~~~
|
||||
etcd [ZONES...] {
|
||||
stubzones
|
||||
fallthrough
|
||||
path PATH
|
||||
endpoint ENDPOINT...
|
||||
upstream ADDRESS...
|
||||
|
@ -33,6 +34,7 @@ etcd [ZONES...] {
|
|||
|
||||
* `stubzones` enables the stub zones feature. The stubzone is *only* done in the etcd tree located
|
||||
under the *first* zone specified.
|
||||
* `fallthrough` If zone matches but no record can be generated, pass request to the next middleware.
|
||||
* **PATH** the path inside etcd. Defaults to "/skydns".
|
||||
* **ENDPOINT** the etcd endpoints. Defaults to "http://localhost:2397".
|
||||
* `upstream` upstream resolvers to be used resolve external names found in etcd (think CNAMEs)
|
||||
|
|
|
@ -21,15 +21,16 @@ import (
|
|||
|
||||
// Etcd is a middleware talks to an etcd cluster.
|
||||
type Etcd struct {
|
||||
Next middleware.Handler
|
||||
Zones []string
|
||||
PathPrefix string
|
||||
Proxy proxy.Proxy // Proxy for looking up names during the resolution process
|
||||
Client etcdc.KeysAPI
|
||||
Ctx context.Context
|
||||
Inflight *singleflight.Group
|
||||
Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
|
||||
Debugging bool // Do we allow debug queries.
|
||||
Next middleware.Handler
|
||||
Fallthrough bool
|
||||
Zones []string
|
||||
PathPrefix string
|
||||
Proxy proxy.Proxy // Proxy for looking up names during the resolution process
|
||||
Client etcdc.KeysAPI
|
||||
Ctx context.Context
|
||||
Inflight *singleflight.Group
|
||||
Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
|
||||
Debugging bool // Do we allow debug queries.
|
||||
|
||||
endpoints []string // Stored here as well, to aid in testing.
|
||||
}
|
||||
|
|
|
@ -46,7 +46,10 @@ func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
|
|||
if opt.Debug != "" {
|
||||
r.Question[0].Name = opt.Debug
|
||||
}
|
||||
return middleware.NextOrFailure(e.Name(), e.Next, ctx, w, r)
|
||||
if e.Fallthrough {
|
||||
return middleware.NextOrFailure(e.Name(), e.Next, ctx, w, r)
|
||||
}
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
func TestMultiLookup(t *testing.T) {
|
||||
etc := newEtcdMiddleware()
|
||||
etc.Zones = []string{"skydns.test.", "miek.nl."}
|
||||
etc.Fallthrough = true
|
||||
etc.Next = test.ErrorHandler()
|
||||
|
||||
for _, serv := range servicesMulti {
|
||||
|
|
|
@ -74,6 +74,8 @@ func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
|
|||
switch c.Val() {
|
||||
case "stubzones":
|
||||
stubzones = true
|
||||
case "fallthrough":
|
||||
etc.Fallthrough = true
|
||||
case "debug":
|
||||
etc.Debugging = true
|
||||
case "path":
|
||||
|
|
|
@ -115,6 +115,8 @@ func fileParse(c *caddy.Controller) (Zones, error) {
|
|||
return Zones{}, err
|
||||
}
|
||||
prxy = proxy.NewLookup(ups)
|
||||
default:
|
||||
return Zones{}, c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
|
||||
for _, origin := range origins {
|
||||
|
|
|
@ -79,6 +79,8 @@ func hostsParse(c *caddy.Controller) (Hosts, error) {
|
|||
continue
|
||||
}
|
||||
return h, c.ArgErr()
|
||||
default:
|
||||
return h, c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func prometheusParse(c *caddy.Controller) (*Metrics, error) {
|
|||
return met, e
|
||||
}
|
||||
default:
|
||||
return met, c.Errf("unknown item: %s", c.Val())
|
||||
return met, c.Errf("unknown property: %s", c.Val())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,9 @@ func TestRegisterPolicy(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
// TODO(miek): Disabled for now, we should get out of the habit of using
|
||||
// realtime in these tests .
|
||||
func testHealthCheck(t *testing.T) {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
|
||||
u := &HealthCheck{
|
||||
|
|
|
@ -88,6 +88,8 @@ func secondaryParse(c *caddy.Controller) (file.Zones, error) {
|
|||
return file.Zones{}, err
|
||||
}
|
||||
prxy = proxy.NewLookup(ups)
|
||||
default:
|
||||
return file.Zones{}, c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
|
||||
for _, origin := range origins {
|
||||
|
|
|
@ -42,6 +42,7 @@ func TestEtcdStubAndProxyLookup(t *testing.T) {
|
|||
path /skydns
|
||||
endpoint http://localhost:2379
|
||||
upstream 8.8.8.8:53 8.8.4.4:53
|
||||
fallthrough
|
||||
}
|
||||
proxy . 8.8.8.8:53
|
||||
}`
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -13,6 +15,10 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
// Test data
|
||||
// TODO: Fix the actual RR values
|
||||
|
||||
|
@ -218,25 +224,6 @@ var dnsTestCases = []test.Case{
|
|||
Rcode: dns.RcodeServerFailure,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
Qname: "123.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
Qname: "100.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("100.0.0.10.in-addr.arpa. 303 IN PTR svc-1-a.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "115.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("115.0.0.10.in-addr.arpa. 303 IN PTR svc-c.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "dns-version.cluster.local.", Qtype: dns.TypeTXT,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
|
@ -244,13 +231,6 @@ var dnsTestCases = []test.Case{
|
|||
test.TXT("dns-version.cluster.local. 28800 IN TXT \"1.0.0\""),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "next-in-chain.", Qtype: dns.TypeA,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.A("next-in-chain. 0 IN A 192.0.2.53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "cluster.local.", Qtype: dns.TypeNS,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
|
@ -303,80 +283,6 @@ var dnsTestCasesPodsVerified = []test.Case{
|
|||
},
|
||||
}
|
||||
|
||||
var dnsTestCasesCidrReverseZone = []test.Case{
|
||||
{
|
||||
Qname: "123.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
Qname: "100.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("100.0.0.10.in-addr.arpa. 303 IN PTR svc-1-a.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "110.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("115.0.0.10.in-addr.arpa. 303 IN PTR svc-1-b.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "115.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("115.0.0.10.in-addr.arpa. 303 IN PTR svc-c.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "next-in-chain.", Qtype: dns.TypeA,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.A("next-in-chain. 0 IN A 192.0.2.53"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var dnsTestCasesPartialCidrReverseZone = []test.Case{
|
||||
{
|
||||
// In exposed range, record not present = OK + No data
|
||||
Qname: "99.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
// In exposed range, record present = OK + Data
|
||||
Qname: "100.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("100.0.0.10.in-addr.arpa. 303 IN PTR svc-1-a.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
// In exposed range, record present = OK + Data
|
||||
Qname: "110.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("115.0.0.10.in-addr.arpa. 303 IN PTR svc-1-b.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
// Out of exposed range, record present = pass to next middleware (not existing in test) = FAIL
|
||||
Qname: "115.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeServerFailure,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
Qname: "next-in-chain.", Qtype: dns.TypeA,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.A("next-in-chain. 0 IN A 192.0.2.53"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var dnsTestCasesAllNSExposed = []test.Case{
|
||||
{
|
||||
Qname: "svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeA,
|
||||
|
@ -392,25 +298,6 @@ var dnsTestCasesAllNSExposed = []test.Case{
|
|||
test.A("svc-c.test-1.svc.cluster.local. 303 IN A 10.0.0.120"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "123.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{},
|
||||
},
|
||||
{
|
||||
Qname: "100.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("100.0.0.10.in-addr.arpa. 303 IN PTR svc-1-a.test-1.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
{
|
||||
Qname: "120.0.0.10.in-addr.arpa.", Qtype: dns.TypePTR,
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Answer: []dns.RR{
|
||||
test.PTR("120.0.0.10.in-addr.arpa. 303 IN PTR svc-c.test-2.svc.cluster.local."),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var dnsTestCasesFallthrough = []test.Case{
|
||||
|
@ -558,42 +445,11 @@ func TestKubernetesIntegrationPodsVerified(t *testing.T) {
|
|||
doIntegrationTests(t, corefile, dnsTestCasesPodsVerified)
|
||||
}
|
||||
|
||||
func TestKubernetesIntegrationCidrReverseZone(t *testing.T) {
|
||||
corefile :=
|
||||
`.:0 {
|
||||
kubernetes cluster.local {
|
||||
endpoint http://localhost:8080
|
||||
namespaces test-1
|
||||
cidrs 10.0.0.0/24
|
||||
}
|
||||
erratic . {
|
||||
drop 0
|
||||
}
|
||||
`
|
||||
doIntegrationTests(t, corefile, dnsTestCasesCidrReverseZone)
|
||||
}
|
||||
|
||||
func TestKubernetesIntegrationPartialCidrReverseZone(t *testing.T) {
|
||||
corefile :=
|
||||
`.:0 {
|
||||
kubernetes cluster.local {
|
||||
endpoint http://localhost:8080
|
||||
namespaces test-1
|
||||
cidrs 10.0.0.96/28 10.0.0.120/32
|
||||
}
|
||||
erratic . {
|
||||
drop 0
|
||||
}
|
||||
`
|
||||
doIntegrationTests(t, corefile, dnsTestCasesPartialCidrReverseZone)
|
||||
}
|
||||
|
||||
func TestKubernetesIntegrationAllNSExposed(t *testing.T) {
|
||||
corefile :=
|
||||
`.:0 {
|
||||
kubernetes cluster.local {
|
||||
endpoint http://localhost:8080
|
||||
cidrs 10.0.0.0/24
|
||||
}
|
||||
`
|
||||
doIntegrationTests(t, corefile, dnsTestCasesAllNSExposed)
|
||||
|
@ -615,7 +471,6 @@ func TestKubernetesIntegrationFallthrough(t *testing.T) {
|
|||
file ` + dbfile + ` cluster.local
|
||||
kubernetes cluster.local {
|
||||
endpoint http://localhost:8080
|
||||
cidrs 10.0.0.0/24
|
||||
namespaces test-1
|
||||
upstream ` + udp + `
|
||||
fallthrough
|
||||
|
|
Loading…
Add table
Reference in a new issue