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:
Miek Gieben 2017-08-14 08:49:26 +01:00 committed by GitHub
parent 818d2b10ad
commit 00f5c7797e
26 changed files with 197 additions and 815 deletions

View file

@ -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())
}
}
}

View file

@ -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)

View file

@ -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.
}

View file

@ -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 (

View file

@ -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 {

View file

@ -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":

View file

@ -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 {

View file

@ -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())
}
}
}

View file

@ -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:

View file

@ -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 ""
}

View file

@ -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: ""})
}

View file

@ -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

View file

@ -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
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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)
}
}
}

View file

@ -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")
}

View file

@ -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)
}
}
}
}

View file

@ -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())
}
}

View file

@ -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{

View file

@ -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 {

View file

@ -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
}`

View file

@ -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