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

Support for multiple targets #243

Closed
wants to merge 1 commit into from
Closed
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
44 changes: 16 additions & 28 deletions controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,20 @@ func (p *mockProvider) Records() ([]*endpoint.Endpoint, error) {

// ApplyChanges validates that the passed in changes satisfy the assumtions.
func (p *mockProvider) ApplyChanges(changes *plan.Changes) error {
if len(changes.Create) != len(p.ExpectChanges.Create) {
return errors.New("number of created records is wrong")
if !testutils.SameEndpoints(p.ExpectChanges.Create, changes.Create) {
return errors.New("created record is wrong")
}

for i := range changes.Create {
if changes.Create[i].DNSName != p.ExpectChanges.Create[i].DNSName || changes.Create[i].Target != p.ExpectChanges.Create[i].Target {
return errors.New("created record is wrong")
}
if !testutils.SameEndpoints(p.ExpectChanges.UpdateNew, changes.UpdateNew) {
return errors.New("created record is wrong")
}

for i := range changes.UpdateNew {
if changes.UpdateNew[i].DNSName != p.ExpectChanges.UpdateNew[i].DNSName || changes.UpdateNew[i].Target != p.ExpectChanges.UpdateNew[i].Target {
return errors.New("delete record is wrong")
}
if !testutils.SameEndpoints(p.ExpectChanges.UpdateOld, changes.UpdateOld) {
return errors.New("created record is wrong")
}

for i := range changes.UpdateOld {
if changes.UpdateOld[i].DNSName != p.ExpectChanges.UpdateOld[i].DNSName || changes.UpdateOld[i].Target != p.ExpectChanges.UpdateOld[i].Target {
return errors.New("delete record is wrong")
}
}

for i := range changes.Delete {
if changes.Delete[i].DNSName != p.ExpectChanges.Delete[i].DNSName || changes.Delete[i].Target != p.ExpectChanges.Delete[i].Target {
return errors.New("delete record is wrong")
}
if !testutils.SameEndpoints(p.ExpectChanges.Delete, changes.Delete) {
return errors.New("created record is wrong")
}

return nil
Expand All @@ -91,11 +79,11 @@ func TestRunOnce(t *testing.T) {
source.On("Endpoints").Return([]*endpoint.Endpoint{
{
DNSName: "create-record",
Target: "1.2.3.4",
Targets: []string{"1.2.3.4"},
},
{
DNSName: "update-record",
Target: "8.8.4.4",
Targets: []string{"8.8.4.4"},
},
}, nil)

Expand All @@ -104,25 +92,25 @@ func TestRunOnce(t *testing.T) {
[]*endpoint.Endpoint{
{
DNSName: "update-record",
Target: "8.8.8.8",
Targets: []string{"8.8.8.8"},
},
{
DNSName: "delete-record",
Target: "4.3.2.1",
Targets: []string{"4.3.2.1"},
},
},
&plan.Changes{
Create: []*endpoint.Endpoint{
{DNSName: "create-record", Target: "1.2.3.4"},
{DNSName: "create-record", Targets: []string{"1.2.3.4"}},
},
UpdateNew: []*endpoint.Endpoint{
{DNSName: "update-record", Target: "8.8.4.4"},
{DNSName: "update-record", Targets: []string{"8.8.4.4"}},
},
UpdateOld: []*endpoint.Endpoint{
{DNSName: "update-record", Target: "8.8.8.8"},
{DNSName: "update-record", Targets: []string{"8.8.8.8"}},
},
Delete: []*endpoint.Endpoint{
{DNSName: "delete-record", Target: "4.3.2.1"},
{DNSName: "delete-record", Targets: []string{"4.3.2.1"}},
},
},
)
Expand Down
30 changes: 23 additions & 7 deletions endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ func (ttl TTL) IsConfigured() bool {
type Endpoint struct {
// The hostname of the DNS record
DNSName string
// The target the DNS record points to
Target string
// The targets the DNS record points to
Targets []string
// RecordType type of record, e.g. CNAME, A, TXT etc
RecordType string
// TTL for the record
Expand All @@ -55,21 +55,37 @@ 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 string, targets []string, recordType string) *Endpoint {
return NewEndpointWithTTL(dnsName, targets, recordType, TTL(0))
}

// 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 string, targets []string, recordType string, ttl TTL) *Endpoint {
for i := range targets {
targets[i] = strings.TrimSuffix(targets[i], ".")
}
return &Endpoint{
DNSName: strings.TrimSuffix(dnsName, "."),
Target: strings.TrimSuffix(target, "."),
Targets: targets,
RecordType: recordType,
Labels: map[string]string{},
RecordTTL: ttl,
}
}

func NewEndpointWithLabels(dnsName string, targets []string, recordType string, labels map[string]string) *Endpoint {
for i := range targets {
targets[i] = strings.TrimSuffix(targets[i], ".")
}
return &Endpoint{
DNSName: strings.TrimSuffix(dnsName, "."),
Targets: targets,
RecordType: recordType,
Labels: labels,
RecordTTL: TTL(0),
}
}

// MergeLabels adds keys to labels if not defined for the endpoint
func (e *Endpoint) MergeLabels(labels map[string]string) {
for k, v := range labels {
Expand All @@ -80,5 +96,5 @@ func (e *Endpoint) MergeLabels(labels map[string]string) {
}

func (e *Endpoint) String() string {
return fmt.Sprintf("%s %d IN %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.Target)
return fmt.Sprintf("%s %d IN %s %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.Targets, e.Labels)
}
28 changes: 23 additions & 5 deletions endpoint/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,40 @@ import (
)

func TestNewEndpoint(t *testing.T) {
e := NewEndpoint("example.org", "foo.com", "CNAME")
if e.DNSName != "example.org" || e.Target != "foo.com" || e.RecordType != "CNAME" {
targets := []string{"foo.com", "bar.com"}
e := NewEndpoint("example.org", targets, "CNAME")
if e.DNSName != "example.org" || e.RecordType != "CNAME" {
t.Error("endpoint is not initialized correctly")
}
if len(e.Targets) != len(targets) {
t.Fatalf("expected %d target(s), got %d", len(targets), len(e.Targets))
}
for i := range e.Targets {
if e.Targets[i] != targets[i] {
t.Error("endpoint is not initialized correctly")
}
}
if e.Labels == nil {
t.Error("Labels is not initialized")
}

w := NewEndpoint("example.org.", "load-balancer.com.", "")
if w.DNSName != "example.org" || w.Target != "load-balancer.com" || w.RecordType != "" {
targets = []string{"load-balancer.com.", "load-balancer.bar."}
w := NewEndpoint("example.org.", targets, "")
if w.DNSName != "example.org" || w.RecordType != "" {
t.Error("endpoint is not initialized correctly")
}
if len(w.Targets) != len(targets) {
t.Fatalf("expected %d target(s), got %d", len(targets), len(w.Targets))
}
for i := range []string{"load-balancer.com", "elb.amazonaws.com"} {
if w.Targets[i] != targets[i] {
t.Error("endpoint is not initialized correctly")
}
}
}

func TestMergeLabels(t *testing.T) {
e := NewEndpoint("abc.com", "1.2.3.4", "A")
e := NewEndpoint("abc.com", []string{"1.2.3.4"}, "A")
e.Labels = map[string]string{
"foo": "bar",
"baz": "qux",
Expand Down
70 changes: 42 additions & 28 deletions internal/testutils/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,51 @@ limitations under the License.

package testutils

import "github.com/kubernetes-incubator/external-dns/endpoint"
import "sort"
import (
"sort"

/** test utility functions for endpoints verifications */
"github.com/kubernetes-incubator/external-dns/endpoint"
)

type byAllFields []*endpoint.Endpoint
// SameEndpoint returns true if two endpoints are same
// considers example.org. and example.org DNSName/Target as different endpoints
func SameEndpoint(a, b *endpoint.Endpoint) bool {
if a.DNSName != b.DNSName {
return false
}

func (b byAllFields) Len() int { return len(b) }
func (b byAllFields) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byAllFields) Less(i, j int) bool {
if b[i].DNSName < b[j].DNSName {
return true
if a.RecordType != b.RecordType {
return false
}
if b[i].DNSName == b[j].DNSName {
if b[i].Target < b[j].Target {
return true
}
if b[i].Target == b[j].Target {
return b[i].RecordType <= b[j].RecordType

if a.RecordTTL != b.RecordTTL {
return false
}

if len(a.Targets) != len(b.Targets) {
return false
}

sort.Strings(a.Targets)
sort.Strings(b.Targets)

for i := range a.Targets {
if a.Targets[i] != b.Targets[i] {
return false
}
}

if len(a.Labels) != len(b.Labels) {
return false
}
return false
}

// SameEndpoint returns true if two endpoints are same
// considers example.org. and example.org DNSName/Target as different endpoints
func SameEndpoint(a, b *endpoint.Endpoint) bool {
return a.DNSName == b.DNSName && a.Target == b.Target && a.RecordType == b.RecordType &&
a.Labels[endpoint.OwnerLabelKey] == b.Labels[endpoint.OwnerLabelKey] && a.RecordTTL == b.RecordTTL
for k := range a.Labels {
if a.Labels[k] != b.Labels[k] {
return false
}
}

return true
}

// SameEndpoints compares two slices of endpoints regardless of order
Expand All @@ -58,16 +73,15 @@ func SameEndpoints(a, b []*endpoint.Endpoint) bool {
return false
}

sa := a[:]
sb := b[:]
sort.Sort(byAllFields(sa))
sort.Sort(byAllFields(sb))
sort.Slice(a, func(i, j int) bool { return a[i].String() < a[j].String() })
sort.Slice(b, func(i, j int) bool { return b[i].String() < b[j].String() })

for i := range sa {
if !SameEndpoint(sa[i], sb[i]) {
for i := range a {
if !SameEndpoint(a[i], b[i]) {
return false
}
}

return true
}

Expand Down
Loading