Unverified Commit f21f45b1 authored by Martin Linkhorst's avatar Martin Linkhorst
Browse files

fix(aws): correctly populate target health check on existing records

parent 7dbd6b0f
......@@ -151,8 +151,21 @@ func NewEndpointWithTTL(dnsName, recordType string, ttl TTL, targets ...string)
}
}
// WithProviderSpecific attaches a key/value pair to the Endpoint and returns the Endpoint.
// This can be used to pass additional data through the stages of ExternalDNS's Endpoint processing.
// The assumption is that most of the time this will be provider specific metadata that doesn't
// warrant its own field on the Endpoint object itself. It differs from Labels in the fact that it's
// not persisted in the Registry but only kept in memory during a single record synchronization.
func (e *Endpoint) WithProviderSpecific(key, value string) *Endpoint {
if e.ProviderSpecific == nil {
e.ProviderSpecific = ProviderSpecific{}
}
e.ProviderSpecific[key] = value
return e
}
func (e *Endpoint) String() string {
return fmt.Sprintf("%s %d IN %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.Targets)
return fmt.Sprintf("%s %d IN %s %s %s", e.DNSName, e.RecordTTL, e.RecordType, e.Targets, e.ProviderSpecific)
}
// DNSEndpointSpec defines the desired state of DNSEndpoint
......
......@@ -48,7 +48,8 @@ func (b byAllFields) Less(i, j int) bool {
func SameEndpoint(a, b *endpoint.Endpoint) bool {
return a.DNSName == b.DNSName && a.Targets.Same(b.Targets) && a.RecordType == b.RecordType &&
a.Labels[endpoint.OwnerLabelKey] == b.Labels[endpoint.OwnerLabelKey] && a.RecordTTL == b.RecordTTL &&
a.Labels[endpoint.ResourceLabelKey] == b.Labels[endpoint.ResourceLabelKey]
a.Labels[endpoint.ResourceLabelKey] == b.Labels[endpoint.ResourceLabelKey] &&
SameMap(a.ProviderSpecific, b.ProviderSpecific)
}
// SameEndpoints compares two slices of endpoints regardless of order
......@@ -79,3 +80,18 @@ func SamePlanChanges(a, b map[string][]*endpoint.Endpoint) bool {
return SameEndpoints(a["Create"], b["Create"]) && SameEndpoints(a["Delete"], b["Delete"]) &&
SameEndpoints(a["UpdateOld"], b["UpdateOld"]) && SameEndpoints(a["UpdateNew"], b["UpdateNew"])
}
// SameMap verifies that two maps contain the same string/string key/value pairs
func SameMap(a, b map[string]string) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if v != b[k] {
return false
}
}
return true
}
......@@ -55,16 +55,22 @@ func ExampleSameEndpoints() {
RecordType: "CNAME",
RecordTTL: endpoint.TTL(60),
},
{
DNSName: "example.org",
Targets: endpoint.Targets{"load-balancer.org"},
ProviderSpecific: endpoint.ProviderSpecific{"foo": "bar"},
},
}
sort.Sort(byAllFields(eps))
for _, ep := range eps {
fmt.Println(ep)
}
// Output:
// abc.com 0 IN A 1.2.3.4
// abc.com 0 IN TXT something
// bbc.com 0 IN CNAME foo.com
// cbc.com 60 IN CNAME foo.com
// example.org 0 IN load-balancer.org
// example.org 0 IN TXT load-balancer.org
// abc.com 0 IN A 1.2.3.4 map[]
// abc.com 0 IN TXT something map[]
// bbc.com 0 IN CNAME foo.com map[]
// cbc.com 60 IN CNAME foo.com map[]
// example.org 0 IN load-balancer.org map[]
// example.org 0 IN load-balancer.org map[foo:bar]
// example.org 0 IN TXT load-balancer.org map[]
}
......@@ -34,6 +34,9 @@ import (
const (
recordTTL = 300
// provider specific key that designates whether an AWS ALIAS record has the EvaluateTargetHealth
// field set to true.
providerSpecificEvaluateTargetHealth = "aws/evaluate-target-health"
)
var (
......@@ -227,7 +230,10 @@ func (p *AWSProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
}
if r.AliasTarget != nil {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeCNAME, ttl, aws.StringValue(r.AliasTarget.DNSName)))
ep := endpoint.
NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeCNAME, ttl, aws.StringValue(r.AliasTarget.DNSName)).
WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", aws.BoolValue(r.AliasTarget.EvaluateTargetHealth)))
endpoints = append(endpoints, ep)
}
}
......@@ -359,11 +365,16 @@ func (p *AWSProvider) newChange(action string, endpoint *endpoint.Endpoint) *rou
}
if isAWSLoadBalancer(endpoint) {
evalTargetHealth := p.evaluateTargetHealth
if _, ok := endpoint.ProviderSpecific[providerSpecificEvaluateTargetHealth]; ok {
evalTargetHealth = endpoint.ProviderSpecific[providerSpecificEvaluateTargetHealth] == "true"
}
change.ResourceRecordSet.Type = aws.String(route53.RRTypeA)
change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{
DNSName: aws.String(endpoint.Targets[0]),
HostedZoneId: aws.String(canonicalHostedZone(endpoint.Targets[0])),
EvaluateTargetHealth: aws.Bool(p.evaluateTargetHealth),
EvaluateTargetHealth: aws.Bool(evalTargetHealth),
}
} else {
change.ResourceRecordSet.Type = aws.String(endpoint.RecordType)
......
......@@ -22,6 +22,7 @@ import (
"sort"
"strings"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53"
......@@ -31,7 +32,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"time"
)
const (
......@@ -249,12 +249,13 @@ func TestAWSZones(t *testing.T) {
}
func TestAWSRecords(t *testing.T) {
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), false, false, []*endpoint.Endpoint{
endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"),
endpoint.NewEndpoint("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"),
endpoint.NewEndpoint("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"),
})
......@@ -265,8 +266,9 @@ func TestAWSRecords(t *testing.T) {
endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"),
endpoint.NewEndpoint("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"),
endpoint.NewEndpoint("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"),
})
}
......@@ -336,12 +338,12 @@ func TestAWSDeleteRecords(t *testing.T) {
endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "baz.elb.amazonaws.com"),
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"),
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"),
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpointWithTTL("delete-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"),
}
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, originalEndpoints)
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), false, false, originalEndpoints)
require.NoError(t, provider.DeleteRecords(originalEndpoints))
......@@ -764,14 +766,22 @@ func TestAWSCreateRecordsWithCNAME(t *testing.T) {
}
func TestAWSCreateRecordsWithALIAS(t *testing.T) {
for _, evaluateTargetHealth := range []bool{
true,
false,
for key, evaluateTargetHealth := range map[string]bool{
"true": true,
"false": false,
"": false,
} {
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), evaluateTargetHealth, false, []*endpoint.Endpoint{})
provider, _ := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{})
records := []*endpoint.Endpoint{
{DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", Targets: endpoint.Targets{"foo.eu-central-1.elb.amazonaws.com"}, RecordType: endpoint.RecordTypeCNAME},
{
DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do",
Targets: endpoint.Targets{"foo.eu-central-1.elb.amazonaws.com"},
RecordType: endpoint.RecordTypeCNAME,
ProviderSpecific: endpoint.ProviderSpecific{
providerSpecificEvaluateTargetHealth: key,
},
},
}
require.NoError(t, provider.CreateRecords(records))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment