Skip to content

Commit

Permalink
Support for multi-target domains
Browse files Browse the repository at this point in the history
This commit adds ability to have several endpoints for single domain
name with CoreDNS by adding random to the DNS name and setting
TargetStrip to 1 so that it will be stripped upon read. When TXT
record is encountered, it is merged with the first available A
record, if any available. Otherwise dedicated record is created.
  • Loading branch information
Stan Lagun committed Jul 3, 2017
1 parent 464d6bd commit 7093280
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 26 deletions.
74 changes: 54 additions & 20 deletions provider/coredns.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ package provider
import (
"container/list"
"encoding/json"
"fmt"
"math/rand"
"strings"
"time"

log "github.com/Sirupsen/logrus"
etcd "github.com/coreos/etcd/client"
Expand All @@ -29,6 +32,10 @@ import (
"github.com/kubernetes-incubator/external-dns/plan"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

// skyDNSClient is an interface to work with SkyDNS service records in etcd
type skyDNSClient interface {
GetServices(prefix string) ([]*Service, error)
Expand Down Expand Up @@ -160,22 +167,26 @@ func (p coreDNSProvider) Records() ([]*endpoint.Endpoint, error) {
for _, service := range services {
domains := strings.Split(strings.TrimPrefix(service.Key, "/skydns/"), "/")
reverse(domains)
dnsName := strings.Join(domains[service.TargetStrip:], ".")
prefix := strings.Join(domains[:service.TargetStrip], ".")
if service.Host != "" {
ep := endpoint.NewEndpoint(
strings.Join(domains, "."),
dnsName,
service.Host,
"",
)
ep.RecordType = suitableType(ep)
ep.Labels["originalText"] = service.Text
ep.Labels["prefix"] = prefix
result = append(result, ep)
}
if service.Text != "" {
ep := endpoint.NewEndpoint(
strings.Join(domains, "."),
dnsName,
service.Text,
"TXT",
)
ep.Labels["prefix"] = prefix
result = append(result, ep)
}
}
Expand All @@ -192,28 +203,47 @@ func (p coreDNSProvider) ApplyChanges(changes *plan.Changes) error {
grouped[ep.DNSName] = append(grouped[ep.DNSName], ep)
}
for dnsName, group := range grouped {
service := Service{}
var services []Service
for _, ep := range group {
recType := suitableType(ep)
switch recType {
case "A", "AAAA":
service.Host = ep.Target
case "CNAME":
if service.Host == "" {
service.Host = ep.Target
}
case "TXT":
service.Text = ep.Target
default:
log.Error("Unsupported record type", recType)
if ep.RecordType == "TXT" {
continue
}
prefix := ep.Labels["prefix"]
if prefix == "" {
prefix = fmt.Sprintf("%08x", rand.Int31())
}
service := Service{
Host: ep.Target,
Text: ep.Labels["originalText"],
Key: etcdKeyFor(prefix + "." + dnsName),
TargetStrip: strings.Count(prefix, ".") + 1,
}
services = append(services, service)
}
index := 0
for _, ep := range group {
if ep.RecordType != "TXT" {
continue
}
if service.Text == "" {
service.Text = ep.Labels["originalText"]
if index >= len(services) {
prefix := ep.Labels["prefix"]
if prefix == "" {
prefix = fmt.Sprintf("%08x", rand.Int31())
}
services = append(services, Service{
Key: etcdKeyFor(prefix + "." + dnsName),
TargetStrip: strings.Count(prefix, ".") + 1,
})
}
services[index].Text = ep.Target
index++
}
if service.Host != "" || service.Text != "" {
service.Key = etcdKeyFor(dnsName)

for i := index; index > 0 && i < len(services); i++ {
services[i].Text = ""
}

for _, service := range services {
log.Infof("Add/set key %s to Host=%s, Text=%s", service.Key, service.Host, service.Text)
if !p.dryRun {
err := p.client.SaveService(&service)
Expand All @@ -225,7 +255,11 @@ func (p coreDNSProvider) ApplyChanges(changes *plan.Changes) error {
}

for _, ep := range changes.Delete {
key := etcdKeyFor(ep.DNSName)
dnsName := ep.DNSName
if ep.Labels["prefix"] != "" {
dnsName = ep.Labels["prefix"] + "." + dnsName
}
key := etcdKeyFor(dnsName)
log.Infof("Delete key %s", key)
if !p.dryRun {
err := p.client.DeleteService(key)
Expand Down
28 changes: 22 additions & 6 deletions provider/coredns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,15 +235,15 @@ func TestCoreDNSApplyChanges(t *testing.T) {
}
validateServices(client.services, expectedServices1, t, 1)

updatedEp := endpoint.NewEndpoint("domain1.local", "6.6.6.6", "A")
updatedEp.Labels["originalText"] = "string1"
changes2 := &plan.Changes{
Create: []*endpoint.Endpoint{
endpoint.NewEndpoint("domain3.local", "7.7.7.7", ""),
},
UpdateNew: []*endpoint.Endpoint{updatedEp},
UpdateNew: []*endpoint.Endpoint{
endpoint.NewEndpoint("domain1.local", "6.6.6.6", "A"),
},
}
coredns.ApplyChanges(changes2)
applyServiceChanges(coredns, changes2)

expectedServices2 := map[string]*Service{
"/skydns/local/domain1": {Host: "6.6.6.6", Text: "string1"},
Expand All @@ -260,20 +260,36 @@ func TestCoreDNSApplyChanges(t *testing.T) {
},
}

coredns.ApplyChanges(changes3)
applyServiceChanges(coredns, changes3)

expectedServices3 := map[string]*Service{
"/skydns/local/domain2": {Host: "site.local"},
}
validateServices(client.services, expectedServices3, t, 3)
}

func applyServiceChanges(provider coreDNSProvider, changes *plan.Changes) {
records, _ := provider.Records()
for _, col := range [][]*endpoint.Endpoint{changes.Create, changes.UpdateNew, changes.Delete} {
for _, record := range col {
for _, existingRecord := range records {
if existingRecord.DNSName == record.DNSName && existingRecord.RecordType == suitableType(record) {
record.MergeLabels(existingRecord.Labels)
}
}
}
}
provider.ApplyChanges(changes)
}

func validateServices(services, expectedServices map[string]*Service, t *testing.T, step int) {
if len(services) != len(expectedServices) {
t.Errorf("wrong number of records on step %d: %d != %d", step, len(services), len(expectedServices))
}
for key, value := range services {
expectedService := expectedServices[key]
keyParts := strings.Split(key, "/")
expectedKey := strings.Join(keyParts[:len(keyParts)-value.TargetStrip], "/")
expectedService := expectedServices[expectedKey]
if expectedService == nil {
t.Errorf("unexpected service %s", key)
continue
Expand Down

0 comments on commit 7093280

Please sign in to comment.