Skip to content
Open
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
51 changes: 38 additions & 13 deletions provider/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ const (
providerSpecificGeoProximityLocationLocalZoneGroup = "aws/geoproximity-local-zone-group"
providerSpecificMultiValueAnswer = "aws/multi-value-answer"
providerSpecificHealthCheckID = "aws/health-check-id"
providerSpecificAliasDisableA = "aws/alias-disable-a"
providerSpecificAliasDisableAAAA = "aws/alias-disable-aaaa"
sameZoneAlias = "same-zone"
// Currently supported up to 10 health checks or hosted zones.
// https://docs.aws.amazon.com/Route53/latest/APIReference/API_ListTagsForResources.html#API_ListTagsForResources_RequestSyntax
Expand Down Expand Up @@ -863,19 +865,32 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoi
ep.SetProviderSpecificProperty(providerSpecificEvaluateTargetHealth, strconv.FormatBool(p.evaluateTargetHealth))
}

if ep.RecordType == endpoint.RecordTypeCNAME {
// This needs to match two records from Route53, one alias for 'A' (IPv4)
// and one alias for 'AAAA' (IPv6).
aliasCnameAaaaEndpoints = append(aliasCnameAaaaEndpoints, &endpoint.Endpoint{
DNSName: ep.DNSName,
Targets: ep.Targets,
RecordType: endpoint.RecordTypeAAAA,
RecordTTL: ep.RecordTTL,
Labels: ep.Labels,
ProviderSpecific: ep.ProviderSpecific,
SetIdentifier: ep.SetIdentifier,
})
ep.RecordType = endpoint.RecordTypeA
disableA := aliasDisableARecord(ep)
disableAaaa := aliasDisableAaaaRecord(ep)
disableAlias := disableA && disableAaaa
enableAandAAAA := !disableA && !disableAaaa

if ep.RecordType == endpoint.RecordTypeCNAME && !disableAlias {
if disableA {
ep.RecordType = endpoint.RecordTypeAAAA
}
if disableAaaa {
ep.RecordType = endpoint.RecordTypeA
}
if enableAandAAAA {
// Add a new endpoint for the AAAA record
aliasCnameAaaaEndpoints = append(aliasCnameAaaaEndpoints, &endpoint.Endpoint{
DNSName: ep.DNSName,
Targets: ep.Targets,
RecordType: endpoint.RecordTypeAAAA,
RecordTTL: ep.RecordTTL,
Labels: ep.Labels,
ProviderSpecific: ep.ProviderSpecific,
SetIdentifier: ep.SetIdentifier,
})
// Modify the original endpoint to be the A record
ep.RecordType = endpoint.RecordTypeA
}
}
} else {
ep.DeleteProviderSpecificProperty(providerSpecificEvaluateTargetHealth)
Expand All @@ -888,6 +903,16 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoi
return endpoints, nil
}

func aliasDisableARecord(ep *endpoint.Endpoint) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion, we will benefit to have a generic,centralised method on Endpoint object for all annotations that contains booleans like true/false

Copy link
Member

@ivankatliarchuk ivankatliarchuk Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like

func (ep *endpoint.Endpoint) GetProviderSpecificBool(key string bool) bool {
	val, ok := ep.GetProviderSpecificProperty(key)
	if !ok {
		return false
	}
	// Normalize whitespace and case; accept common truthy values
	v := strings.TrimSpace(strings.ToLower(val))
	switch v {
	case "1", "t", "true", "yes", "y":
		return true
	case "0", "f", "false", "no", "n":
		return false
	default:		
		return false
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does sound like a good idea.
However, in this change we’re going to use values other than just true/false, as @mloiseleur mentioned, and I’m a bit concerned that introducing a generic, centralized method here would make the scope of this PR too large.
I’d prefer to handle that refactor in a separate PR that can apply the change across the whole codebase. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

disable, ok := ep.GetProviderSpecificProperty(providerSpecificAliasDisableA)
return ok && disable == "true"
}

func aliasDisableAaaaRecord(ep *endpoint.Endpoint) bool {
disable, ok := ep.GetProviderSpecificProperty(providerSpecificAliasDisableAAAA)
return ok && disable == "true"
}

// if the endpoint is using geoproximity, set the bias to 0 if not set
// this is needed to avoid unnecessary Upserts if the desired endpoint doesn't specify a bias
func adjustGeoProximityLocationEndpoint(ep *endpoint.Endpoint) {
Expand Down
6 changes: 6 additions & 0 deletions provider/aws/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,9 @@ func TestAWSAdjustEndpoints(t *testing.T) {
endpoint.NewEndpoint("cname-test-elb-no-eth.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), // eth = evaluate target health
endpoint.NewEndpoint("cname-test-elb-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpoint("a-test-geoproximity-no-bias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeoProximityLocationAWSRegion, "us-west-2"),
endpoint.NewEndpoint("same-zone-alias-test.teapot.zalan.do", endpoint.RecordTypeCNAME, "same-zone-alias-target.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableA, "true"),
endpoint.NewEndpoint("same-zone-alias-test2.teapot.zalan.do", endpoint.RecordTypeCNAME, "same-zone-alias-target2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableAAAA, "true"),
endpoint.NewEndpoint("same-zone-alias-test3.teapot.zalan.do", endpoint.RecordTypeCNAME, "same-zone-alias-target3.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableA, "true").WithProviderSpecific(providerSpecificAliasDisableAAAA, "true"),
}

records, err := provider.AdjustEndpoints(records)
Expand All @@ -728,6 +731,9 @@ func TestAWSAdjustEndpoints(t *testing.T) {
endpoint.NewEndpoint("cname-test-elb-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpoint("cname-test-elb-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpoint("a-test-geoproximity-no-bias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeoProximityLocationAWSRegion, "us-west-2").WithProviderSpecific(providerSpecificGeoProximityLocationBias, "0"),
endpoint.NewEndpoint("same-zone-alias-test.teapot.zalan.do", endpoint.RecordTypeAAAA, "same-zone-alias-target.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableA, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpoint("same-zone-alias-test2.teapot.zalan.do", endpoint.RecordTypeA, "same-zone-alias-target2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableAAAA, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
endpoint.NewEndpoint("same-zone-alias-test3.teapot.zalan.do", endpoint.RecordTypeCNAME, "same-zone-alias-target3.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificAliasDisableA, "true").WithProviderSpecific(providerSpecificAliasDisableAAAA, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"),
})
}

Expand Down
Loading