diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 70f3b0562c..468a8d4f39 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -435,6 +435,39 @@ func (p *AWSProvider) UpdateRecords(ctx context.Context, updates, current []*end return p.submitChanges(ctx, p.createUpdateChanges(updates, current), zones) } +// Identify if old and new endpoints require DELETE/CREATE instead of UPDATE. +func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, new *endpoint.Endpoint) bool { + + // a change of record type + if old.RecordType != new.RecordType { + return true + } + + // an ALIAS record change to/from a CNAME + if old.RecordType == endpoint.RecordTypeCNAME && useAlias(old, p.preferCNAME) != useAlias(new, p.preferCNAME) { + return true + } + + // a change of routing policy + // default to true for geolocation properties if any geolocation property exists in old/new but not the other + for _, propType := range [7]string{providerSpecificWeight, providerSpecificRegion, providerSpecificFailover, + providerSpecificFailover, providerSpecificGeolocationContinentCode, providerSpecificGeolocationCountryCode, + providerSpecificGeolocationSubdivisionCode} { + _, oldPolicy := old.GetProviderSpecificProperty(propType) + _, newPolicy := old.GetProviderSpecificProperty(propType) + if oldPolicy != newPolicy { + return true + } + } + + // a set identifier change + if old.SetIdentifier != new.SetIdentifier { + return true + } + + return false +} + func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint.Endpoint) []*route53.Change { var deletes []*endpoint.Endpoint var creates []*endpoint.Endpoint @@ -442,12 +475,7 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint for i, new := range newEndpoints { old := oldEndpoints[i] - if new.RecordType != old.RecordType || - // Handle the case where an AWS ALIAS record is changing to/from a CNAME. - (old.RecordType == endpoint.RecordTypeCNAME && useAlias(old, p.preferCNAME) != useAlias(new, p.preferCNAME)) || - // Handle the case where an AWS record is changing to/from simple to other routing policies - ((old.SetIdentifier == "" && new.SetIdentifier != "") || (old.SetIdentifier != "" && new.SetIdentifier == "")) { - // The record type changed or the routing policy change, so UPSERT will fail. Instead perform a DELETE followed by a CREATE. + if p.requiresDeleteCreate(old, new) { deletes = append(deletes, old) creates = append(creates, new) } else { diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index c7c99ee16f..f6363bad7e 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -529,6 +529,8 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpointWithTTL("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("weighted-to-simple").WithProviderSpecific(providerSpecificWeight, "10"), endpoint.NewEndpointWithTTL("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), endpoint.NewEndpointWithTTL("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("policy-change").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpointWithTTL("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("before").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpointWithTTL("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("no-change").WithProviderSpecific(providerSpecificWeight, "10"), }) createRecords := []*endpoint.Endpoint{ @@ -550,6 +552,8 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("weighted-to-simple").WithProviderSpecific(providerSpecificWeight, "10"), endpoint.NewEndpoint("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), endpoint.NewEndpoint("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("policy-change").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpoint("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("before").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpoint("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("no-change").WithProviderSpecific(providerSpecificWeight, "10"), } updatedRecords := []*endpoint.Endpoint{ endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), @@ -562,6 +566,8 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), endpoint.NewEndpoint("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("simple-to-weighted").WithProviderSpecific(providerSpecificWeight, "10"), endpoint.NewEndpoint("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("policy-change").WithProviderSpecific(providerSpecificRegion, "us-east-1"), + endpoint.NewEndpoint("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("after").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpoint("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4").WithSetIdentifier("no-change").WithProviderSpecific(providerSpecificWeight, "10"), } deleteRecords := []*endpoint.Endpoint{ @@ -608,6 +614,8 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpointWithTTL("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), endpoint.NewEndpointWithTTL("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("simple-to-weighted").WithProviderSpecific(providerSpecificWeight, "10"), endpoint.NewEndpointWithTTL("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("policy-change").WithProviderSpecific(providerSpecificRegion, "us-east-1"), + endpoint.NewEndpointWithTTL("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("after").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpointWithTTL("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("no-change").WithProviderSpecific(providerSpecificWeight, "10"), }) } }