Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First pass at a stubzones bugfix #310

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions backends/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func NewBackend(client etcd.KeysAPI, ctx context.Context, config *Config) *Backe
}
}

func (g *Backend) Records(name string, exact bool) ([]msg.Service, error) {
func (g *Backend) Records(name string, exact bool, stub bool) ([]msg.Service, error) {
path, star := msg.PathWithWildcard(name)
r, err := g.get(path, true)
if err != nil {
Expand All @@ -53,9 +53,9 @@ func (g *Backend) Records(name string, exact bool) ([]msg.Service, error) {
case exact && r.Node.Dir:
return nil, nil
case r.Node.Dir:
return g.loopNodes(r.Node.Nodes, segments, star, nil)
return g.loopNodes(r.Node.Nodes, segments, star, stub, nil)
default:
return g.loopNodes([]*etcd.Node{r.Node}, segments, false, nil)
return g.loopNodes([]*etcd.Node{r.Node}, segments, false, stub, nil)
}
}

Expand All @@ -72,7 +72,7 @@ func (g *Backend) ReverseRecord(name string) (*msg.Service, error) {
return nil, fmt.Errorf("reverse must not be a directory")
}
segments := strings.Split(msg.Path(name), "/")
records, err := g.loopNodes([]*etcd.Node{r.Node}, segments, false, nil)
records, err := g.loopNodes([]*etcd.Node{r.Node}, segments, false, false, nil)
if err != nil {
return nil, err
}
Expand All @@ -99,11 +99,12 @@ func (g *Backend) get(path string, recursive bool) (*etcd.Response, error) {
}

type bareService struct {
Host string
Port int
Priority int
Weight int
Text string
Host string
Port int
Priority int
Weight int
Text string
SubDomain string
}

// skydns/local/skydns/east/staging/web
Expand All @@ -114,14 +115,14 @@ type bareService struct {

// loopNodes recursively loops through the nodes and returns all the values. The nodes' keyname
// will be match against any wildcards when star is true.
func (g *Backend) loopNodes(ns []*etcd.Node, nameParts []string, star bool, bx map[bareService]bool) (sx []msg.Service, err error) {
func (g *Backend) loopNodes(ns []*etcd.Node, nameParts []string, star bool, stub bool, bx map[bareService]bool) (sx []msg.Service, err error) {
if bx == nil {
bx = make(map[bareService]bool)
}
Nodes:
for _, n := range ns {
if n.Dir {
nodes, err := g.loopNodes(n.Nodes, nameParts, star, bx)
nodes, err := g.loopNodes(n.Nodes, nameParts, star, stub, bx)
if err != nil {
return nil, err
}
Expand All @@ -147,7 +148,13 @@ Nodes:
if err := json.Unmarshal([]byte(n.Value), serv); err != nil {
return nil, err
}
b := bareService{serv.Host, serv.Port, serv.Priority, serv.Weight, serv.Text}
subdomain := ""
if stub {
index := strings.LastIndex(n.Key, "/")
subdomain = string(n.Key[0:index])

}
b := bareService{serv.Host, serv.Port, serv.Priority, serv.Weight, serv.Text, subdomain}
if _, ok := bx[b]; ok {
continue
}
Expand Down
74 changes: 74 additions & 0 deletions backends/etcd/etcd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2015 All Right Reserved, Improbable Worlds Ltd.

package etcd

import (
"encoding/json"
"os"
"testing"
"time"

etcd "github.com/coreos/etcd/client"
etcd_harness "github.com/mwitkow/go-etcd-harness"
"github.com/skynetservices/skydns/msg"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"golang.org/x/net/context"
)

type etcdBackendTestSuite struct {
suite.Suite
etcdBackend *Backend
}

func (s *etcdBackendTestSuite) SetupTest() {
s.etcdBackend.client.Delete(context.TODO(), "skydns", &etcd.DeleteOptions{Recursive: true, Dir: true})
}

func (s *etcdBackendTestSuite) TestGettingSingleRecordShouldReturnCorrectService() {
s.createEtcdRecord(msg.Service{Host: "1.1.1.1", Key: "/skydns/com/test"})
records, err := s.etcdBackend.Records("test.com", true, false)
assert.NoError(s.T(), err, "no err")
assert.Equal(s.T(), 1, len(records))
assert.Equal(s.T(), "1.1.1.1", records[0].Host)
}

func (s *etcdBackendTestSuite) TestStubZone() {
s.createEtcdRecord(msg.Service{Host: "1.1.1.1", Key: "/skydns/com/test/dns/stub/com/othertest/a/stubzone1/a"})
s.createEtcdRecord(msg.Service{Host: "1.1.1.2", Key: "/skydns/com/test/dns/stub/com/othertest/a/stubzone1/b"})
s.createEtcdRecord(msg.Service{Host: "1.1.1.1", Key: "/skydns/com/test/dns/stub/com/othertest/stubzone2/b"})
s.createEtcdRecord(msg.Service{Host: "1.1.1.2", Key: "/skydns/com/test/dns/stub/com/othertest/stubzone2/a"})
records, err := s.etcdBackend.Records("stub.dns.test.com", false, true)
assert.NoError(s.T(), err)
assert.Equal(s.T(), 4, len(records))
}

func TestDeploymentServiceSuite(t *testing.T) {
if testing.Short() {
t.Skipf("DeploymentServiceSuite is a long integration test suite. Skipping due to test short.")
}
if !etcd_harness.LocalEtcdAvailable() {
t.Skipf("etcd is not available in $PATH, skipping suite")
}

server, err := etcd_harness.New(os.Stderr)
if err != nil {
t.Fatalf("failed starting test server: %v", err)
}
t.Logf("will use etcd test endpoint: %v", server.Endpoint)
defer func() {
server.Stop()
t.Logf("cleaned up etcd test server")
}()
etcdClient := etcd.NewKeysAPI(server.Client)
suite.Run(t, &etcdBackendTestSuite{etcdBackend: NewBackend(etcdClient, context.TODO(), &Config{})})
}

func (s *etcdBackendTestSuite) createEtcdRecord(srv msg.Service) {
ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
value, err := json.Marshal(srv)
require.NoError(s.T(), err, "marshaling etcd record should not fail")
_, err = s.etcdBackend.client.Create(ctx, srv.Key, string(value))
require.NoError(s.T(), err, "creating etcd record should not fail")
}
2 changes: 1 addition & 1 deletion backends/etcd3/etcd3.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func NewBackendv3 (client etcdv3.Client, ctx context.Context, config *Config) *B
}
}

func (g *Backendv3) Records(name string, exact bool) ([]msg.Service, error) {
func (g *Backendv3) Records(name string, exact bool, stub bool) ([]msg.Service, error) {
path, star := msg.PathWithWildcard(name)
r, err := g.get(path, true)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions server/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package server
import "github.com/skynetservices/skydns/msg"

type Backend interface {
Records(name string, exact bool) ([]msg.Service, error)
Records(name string, exact bool, stub bool) ([]msg.Service, error)
ReverseRecord(name string) (*msg.Service, error)
}

Expand All @@ -19,10 +19,10 @@ type FirstBackend []Backend
// FirstBackend implements Backend
var _ Backend = FirstBackend{}

func (g FirstBackend) Records(name string, exact bool) (records []msg.Service, err error) {
func (g FirstBackend) Records(name string, exact bool, stub bool) (records []msg.Service, err error) {
var lastError error
for _, backend := range g {
if records, err = backend.Records(name, exact); err == nil && len(records) > 0 {
if records, err = backend.Records(name, exact, stub); err == nil && len(records) > 0 {
return records, nil
}
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
}

func (s *server) AddressRecords(q dns.Question, name string, previousRecords []dns.RR, bufsize uint16, dnssec, both bool) (records []dns.RR, err error) {
services, err := s.backend.Records(name, false)
services, err := s.backend.Records(name, false, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -485,7 +485,7 @@ func (s *server) AddressRecords(q dns.Question, name string, previousRecords []d

// NSRecords returns NS records from etcd.
func (s *server) NSRecords(q dns.Question, name string) (records []dns.RR, extra []dns.RR, err error) {
services, err := s.backend.Records(name, false)
services, err := s.backend.Records(name, false, false)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -513,7 +513,7 @@ func (s *server) NSRecords(q dns.Question, name string) (records []dns.RR, extra
// SRVRecords returns SRV records from etcd.
// If the Target is not a name but an IP address, a name is created.
func (s *server) SRVRecords(q dns.Question, name string, bufsize uint16, dnssec bool) (records []dns.RR, extra []dns.RR, err error) {
services, err := s.backend.Records(name, false)
services, err := s.backend.Records(name, false, false)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -598,7 +598,7 @@ func (s *server) SRVRecords(q dns.Question, name string, bufsize uint16, dnssec
// MXRecords returns MX records from etcd.
// If the Target is not a name but an IP address, a name is created.
func (s *server) MXRecords(q dns.Question, name string, bufsize uint16, dnssec bool) (records []dns.RR, extra []dns.RR, err error) {
services, err := s.backend.Records(name, false)
services, err := s.backend.Records(name, false, false)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -655,7 +655,7 @@ func (s *server) MXRecords(q dns.Question, name string, bufsize uint16, dnssec b
}

func (s *server) CNAMERecords(q dns.Question, name string) (records []dns.RR, err error) {
services, err := s.backend.Records(name, true)
services, err := s.backend.Records(name, true, false)
if err != nil {
return nil, err
}
Expand All @@ -672,7 +672,7 @@ func (s *server) CNAMERecords(q dns.Question, name string) (records []dns.RR, er
}

func (s *server) TXTRecords(q dns.Question, name string) (records []dns.RR, err error) {
services, err := s.backend.Records(name, false)
services, err := s.backend.Records(name, false, false)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion server/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var ednsStub = func() *dns.OPT {
func (s *server) UpdateStubZones() {
stubmap := make(map[string][]string)

services, err := s.backend.Records("stub.dns."+s.config.Domain, false)
services, err := s.backend.Records("stub.dns."+s.config.Domain, false, true)
if err != nil {
logf("stub zone update failed: %s", err)
return
Expand Down