Skip to content

Commit

Permalink
Merge pull request #493 from grimmy/issue-239-multiple-targets
Browse files Browse the repository at this point in the history
Inititial support for multiple targets per record
  • Loading branch information
njuettner authored Apr 18, 2018
2 parents f93ed1f + 4d532e2 commit 68be609
Show file tree
Hide file tree
Showing 20 changed files with 389 additions and 314 deletions.
13 changes: 9 additions & 4 deletions endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,20 @@ type Endpoint struct {
}

// NewEndpoint initialization method to be used to create an endpoint
func NewEndpoint(dnsName, target, recordType string) *Endpoint {
return NewEndpointWithTTL(dnsName, target, recordType, TTL(0))
func NewEndpoint(dnsName, recordType string, targets ...string) *Endpoint {
return NewEndpointWithTTL(dnsName, recordType, TTL(0), targets...)
}

// NewEndpointWithTTL initialization method to be used to create an endpoint with a TTL struct
func NewEndpointWithTTL(dnsName, target, recordType string, ttl TTL) *Endpoint {
func NewEndpointWithTTL(dnsName, recordType string, ttl TTL, targets ...string) *Endpoint {
cleanTargets := make([]string, len(targets))
for idx, target := range targets {
cleanTargets[idx] = strings.TrimSuffix(target, ".")
}

return &Endpoint{
DNSName: strings.TrimSuffix(dnsName, "."),
Targets: Targets{strings.TrimSuffix(target, ".")},
Targets: cleanTargets,
RecordType: recordType,
Labels: NewLabels(),
RecordTTL: ttl,
Expand Down
45 changes: 43 additions & 2 deletions endpoint/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,57 @@ import (
)

func TestNewEndpoint(t *testing.T) {
e := NewEndpoint("example.org", "foo.com", "CNAME")
e := NewEndpoint("example.org", "CNAME", "foo.com")
if e.DNSName != "example.org" || e.Targets[0] != "foo.com" || e.RecordType != "CNAME" {
t.Error("endpoint is not initialized correctly")
}
if e.Labels == nil {
t.Error("Labels is not initialized")
}

w := NewEndpoint("example.org.", "load-balancer.com.", "")
w := NewEndpoint("example.org.", "", "load-balancer.com.")
if w.DNSName != "example.org" || w.Targets[0] != "load-balancer.com" || w.RecordType != "" {
t.Error("endpoint is not initialized correctly")
}
}

func TestTargetsSame(t *testing.T) {
tests := []Targets{
{""},
{"1.2.3.4"},
{"8.8.8.8", "8.8.4.4"},
}

for _, d := range tests {
if d.Same(d) != true {
t.Errorf("%#v should equal %#v", d, d)
}
}
}

func TestSameFailures(t *testing.T) {
tests := []struct {
a Targets
b Targets
}{
{
[]string{"1.2.3.4"},
[]string{"4.3.2.1"},
}, {
[]string{"1.2.3.4"},
[]string{"1.2.3.4", "4.3.2.1"},
}, {
[]string{"1.2.3.4", "4.3.2.1"},
[]string{"1.2.3.4"},
}, {
[]string{"1.2.3.4", "4.3.2.1"},
[]string{"8.8.8.8", "8.8.4.4"},
},
}

for _, d := range tests {
if d.a.Same(d.b) == true {
t.Errorf("%#v should not equal %#v", d.a, d.b)
}
}
}
20 changes: 13 additions & 7 deletions provider/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,17 @@ func (p *AWSProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
ttl = endpoint.TTL(*r.TTL)
}

for _, rr := range r.ResourceRecords {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), aws.StringValue(rr.Value), aws.StringValue(r.Type), ttl))
if len(r.ResourceRecords) > 0 {
targets := make([]string, len(r.ResourceRecords))
for idx, rr := range r.ResourceRecords {
targets[idx] = aws.StringValue(rr.Value)
}

endpoints = append(endpoints, endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), aws.StringValue(r.Type), ttl, targets...))
}

if r.AliasTarget != nil {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), aws.StringValue(r.AliasTarget.DNSName), endpoint.RecordTypeCNAME, ttl))
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeCNAME, ttl, aws.StringValue(r.AliasTarget.DNSName)))
}
}

Expand Down Expand Up @@ -389,10 +394,11 @@ func newChange(action string, endpoint *endpoint.Endpoint) *route53.Change {
} else {
change.ResourceRecordSet.TTL = aws.Int64(int64(endpoint.RecordTTL))
}
change.ResourceRecordSet.ResourceRecords = []*route53.ResourceRecord{
{
Value: aws.String(endpoint.Targets[0]),
},
change.ResourceRecordSet.ResourceRecords = make([]*route53.ResourceRecord, len(endpoint.Targets))
for idx, val := range endpoint.Targets {
change.ResourceRecordSet.ResourceRecords[idx] = &route53.ResourceRecord{
Value: aws.String(val),
}
}
}

Expand Down
207 changes: 115 additions & 92 deletions provider/aws_test.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion provider/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (p *AzureProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
ttl = endpoint.TTL(*recordSet.TTL)
}

ep := endpoint.NewEndpointWithTTL(name, target, recordType, endpoint.TTL(ttl))
ep := endpoint.NewEndpointWithTTL(name, recordType, endpoint.TTL(ttl), target)
log.Debugf(
"Found %s record for '%s' with target '%s'.",
ep.RecordType,
Expand Down
80 changes: 40 additions & 40 deletions provider/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ func (client *mockRecordsClient) Delete(resourceGroupName string, zoneName strin
client.deletedEndpoints,
endpoint.NewEndpoint(
formatAzureDNSName(relativeRecordSetName, zoneName),
"",
string(recordType),
"",
),
)
return autorest.Response{}, nil
Expand All @@ -145,9 +145,9 @@ func (client *mockRecordsClient) CreateOrUpdate(resourceGroupName string, zoneNa
client.updatedEndpoints,
endpoint.NewEndpointWithTTL(
formatAzureDNSName(relativeRecordSetName, zoneName),
extractAzureTarget(&parameters),
string(recordType),
ttl,
extractAzureTarget(&parameters),
),
)
return parameters, nil
Expand Down Expand Up @@ -197,11 +197,11 @@ func TestAzureRecord(t *testing.T) {
t.Fatal(err)
}
expected := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", "123.123.123.122", endpoint.RecordTypeA),
endpoint.NewEndpoint("example.com", "heritage=external-dns,external-dns/owner=default", endpoint.RecordTypeTXT),
endpoint.NewEndpointWithTTL("nginx.example.com", "123.123.123.123", endpoint.RecordTypeA, 3600),
endpoint.NewEndpointWithTTL("nginx.example.com", "heritage=external-dns,external-dns/owner=default", endpoint.RecordTypeTXT, recordTTL),
endpoint.NewEndpointWithTTL("hack.example.com", "hack.azurewebsites.net", endpoint.RecordTypeCNAME, 10),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
endpoint.NewEndpointWithTTL("nginx.example.com", endpoint.RecordTypeA, 3600, "123.123.123.123"),
endpoint.NewEndpointWithTTL("nginx.example.com", endpoint.RecordTypeTXT, recordTTL, "heritage=external-dns,external-dns/owner=default"),
endpoint.NewEndpointWithTTL("hack.example.com", endpoint.RecordTypeCNAME, 10, "hack.azurewebsites.net"),
}

validateAzureEndpoints(t, actual, expected)
Expand All @@ -214,23 +214,23 @@ func TestAzureApplyChanges(t *testing.T) {
testAzureApplyChangesInternal(t, false, &recordsClient)

validateAzureEndpoints(t, recordsClient.deletedEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpoint("old.example.com", "", endpoint.RecordTypeA),
endpoint.NewEndpoint("oldcname.example.com", "", endpoint.RecordTypeCNAME),
endpoint.NewEndpoint("deleted.example.com", "", endpoint.RecordTypeA),
endpoint.NewEndpoint("deletedcname.example.com", "", endpoint.RecordTypeCNAME),
endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, ""),
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, ""),
})

validateAzureEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpointWithTTL("example.com", "1.2.3.4", endpoint.RecordTypeA, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("foo.example.com", "1.2.3.4", endpoint.RecordTypeA, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("foo.example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("bar.example.com", "other.com", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("bar.example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("other.com", "5.6.7.8", endpoint.RecordTypeA, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("other.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)),
endpoint.NewEndpointWithTTL("new.example.com", "111.222.111.222", endpoint.RecordTypeA, 3600),
endpoint.NewEndpointWithTTL("newcname.example.com", "other.com", endpoint.RecordTypeCNAME, 10),
endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("foo.example.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("foo.example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("bar.example.com", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "other.com"),
endpoint.NewEndpointWithTTL("bar.example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("other.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "5.6.7.8"),
endpoint.NewEndpointWithTTL("other.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("new.example.com", endpoint.RecordTypeA, 3600, "111.222.111.222"),
endpoint.NewEndpointWithTTL("newcname.example.com", endpoint.RecordTypeCNAME, 10, "other.com"),
})
}

Expand Down Expand Up @@ -262,33 +262,33 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClie
)

createRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", "1.2.3.4", endpoint.RecordTypeA),
endpoint.NewEndpoint("example.com", "tag", endpoint.RecordTypeTXT),
endpoint.NewEndpoint("foo.example.com", "1.2.3.4", endpoint.RecordTypeA),
endpoint.NewEndpoint("foo.example.com", "tag", endpoint.RecordTypeTXT),
endpoint.NewEndpoint("bar.example.com", "other.com", endpoint.RecordTypeCNAME),
endpoint.NewEndpoint("bar.example.com", "tag", endpoint.RecordTypeTXT),
endpoint.NewEndpoint("other.com", "5.6.7.8", endpoint.RecordTypeA),
endpoint.NewEndpoint("other.com", "tag", endpoint.RecordTypeTXT),
endpoint.NewEndpoint("nope.com", "4.4.4.4", endpoint.RecordTypeA),
endpoint.NewEndpoint("nope.com", "tag", endpoint.RecordTypeTXT),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("nope.com", endpoint.RecordTypeA, "4.4.4.4"),
endpoint.NewEndpoint("nope.com", endpoint.RecordTypeTXT, "tag"),
}

currentRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("old.example.com", "121.212.121.212", endpoint.RecordTypeA),
endpoint.NewEndpoint("oldcname.example.com", "other.com", endpoint.RecordTypeCNAME),
endpoint.NewEndpoint("old.nope.com", "121.212.121.212", endpoint.RecordTypeA),
endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, "121.212.121.212"),
endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("old.nope.com", endpoint.RecordTypeA, "121.212.121.212"),
}
updatedRecords := []*endpoint.Endpoint{
endpoint.NewEndpointWithTTL("new.example.com", "111.222.111.222", endpoint.RecordTypeA, 3600),
endpoint.NewEndpointWithTTL("newcname.example.com", "other.com", endpoint.RecordTypeCNAME, 10),
endpoint.NewEndpoint("new.nope.com", "222.111.222.111", endpoint.RecordTypeA),
endpoint.NewEndpointWithTTL("new.example.com", endpoint.RecordTypeA, 3600, "111.222.111.222"),
endpoint.NewEndpointWithTTL("newcname.example.com", endpoint.RecordTypeCNAME, 10, "other.com"),
endpoint.NewEndpoint("new.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
}

deleteRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("deleted.example.com", "111.222.111.222", endpoint.RecordTypeA),
endpoint.NewEndpoint("deletedcname.example.com", "other.com", endpoint.RecordTypeCNAME),
endpoint.NewEndpoint("deleted.nope.com", "222.111.222.111", endpoint.RecordTypeA),
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, "111.222.111.222"),
endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("deleted.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
}

changes := &plan.Changes{
Expand Down
2 changes: 1 addition & 1 deletion provider/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (p *CloudFlareProvider) Records() ([]*endpoint.Endpoint, error) {

for _, r := range records {
if supportedRecordType(r.Type) {
endpoints = append(endpoints, endpoint.NewEndpoint(r.Name, r.Content, r.Type))
endpoints = append(endpoints, endpoint.NewEndpoint(r.Name, r.Type, r.Content))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion provider/designate.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (p designateProvider) Records() ([]*endpoint.Endpoint, error) {
return nil
}
for _, record := range recordSet.Records {
ep := endpoint.NewEndpoint(recordSet.Name, record, recordSet.Type)
ep := endpoint.NewEndpoint(recordSet.Name, recordSet.Type, record)
ep.Labels[designateRecordSetID] = recordSet.ID
ep.Labels[designateZoneID] = recordSet.ZoneID
ep.Labels[designateOriginalRecords] = strings.Join(recordSet.Records, "\000")
Expand Down
2 changes: 1 addition & 1 deletion provider/digital_ocean.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (p *DigitalOceanProvider) Records() ([]*endpoint.Endpoint, error) {
name = zone.Name
}

endpoints = append(endpoints, endpoint.NewEndpoint(name, r.Data, r.Type))
endpoints = append(endpoints, endpoint.NewEndpoint(name, r.Type, r.Data))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion provider/dnsimple.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (p *dnsimpleProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
default:
continue
}
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(record.Name+"."+record.ZoneID, record.Content, record.Type, endpoint.TTL(record.TTL)))
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(record.Name+"."+record.ZoneID, record.Type, endpoint.TTL(record.TTL), record.Content))
}
page++
if page > records.Pagination.TotalPages {
Expand Down
16 changes: 8 additions & 8 deletions provider/dyn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ func TestDyn_endpointToRecord(t *testing.T) {
ep *endpoint.Endpoint
extractor func(*dynect.DataBlock) string
}{
{endpoint.NewEndpoint("address", "the-target", "A"), func(b *dynect.DataBlock) string { return b.Address }},
{endpoint.NewEndpoint("cname", "the-target", "CNAME"), func(b *dynect.DataBlock) string { return b.CName }},
{endpoint.NewEndpoint("text", "the-target", "TXT"), func(b *dynect.DataBlock) string { return b.TxtData }},
{endpoint.NewEndpoint("address", "A", "the-target"), func(b *dynect.DataBlock) string { return b.Address }},
{endpoint.NewEndpoint("cname", "CNAME", "the-target"), func(b *dynect.DataBlock) string { return b.CName }},
{endpoint.NewEndpoint("text", "TXT", "the-target"), func(b *dynect.DataBlock) string { return b.TxtData }},
}

for _, tc := range tests {
Expand All @@ -213,11 +213,11 @@ func TestDyn_buildLinkToRecord(t *testing.T) {
ep *endpoint.Endpoint
link string
}{
{endpoint.NewEndpoint("sub.the-target.example.com", "address", "A"), "ARecord/example.com/sub.the-target.example.com/"},
{endpoint.NewEndpoint("the-target.example.com", "cname", "CNAME"), "CNAMERecord/example.com/the-target.example.com/"},
{endpoint.NewEndpoint("the-target.example.com", "text", "TXT"), "TXTRecord/example.com/the-target.example.com/"},
{endpoint.NewEndpoint("the-target.google.com", "text", "TXT"), ""},
{endpoint.NewEndpoint("mail.example.com", "text", "TXT"), ""},
{endpoint.NewEndpoint("sub.the-target.example.com", "A", "address"), "ARecord/example.com/sub.the-target.example.com/"},
{endpoint.NewEndpoint("the-target.example.com", "CNAME", "cname"), "CNAMERecord/example.com/the-target.example.com/"},
{endpoint.NewEndpoint("the-target.example.com", "TXT", "text"), "TXTRecord/example.com/the-target.example.com/"},
{endpoint.NewEndpoint("the-target.google.com", "TXT", "text"), ""},
{endpoint.NewEndpoint("mail.example.com", "TXT", "text"), ""},
{nil, ""},
}

Expand Down
Loading

0 comments on commit 68be609

Please sign in to comment.