From fe5799a05356a2dafa7be5ddc09c0271e261ab3c Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Thu, 11 May 2023 21:33:21 -0700 Subject: [PATCH 1/3] Always create AAAA alias records in route53 --- .../tutorials/aws-load-balancer-controller.md | 39 ------ docs/tutorials/kube-ingress-aws.md | 47 +------ endpoint/labels.go | 3 - provider/aws/aws.go | 44 ++++--- provider/aws/aws_test.go | 123 +++++++++++++++--- source/ingress.go | 16 --- source/ingress_test.go | 18 +-- source/kong_tcpingress.go | 11 -- source/skipper_routegroup.go | 11 -- source/skipper_routegroup_test.go | 31 ----- source/traefik_proxy.go | 34 ----- 11 files changed, 137 insertions(+), 240 deletions(-) diff --git a/docs/tutorials/aws-load-balancer-controller.md b/docs/tutorials/aws-load-balancer-controller.md index 98bc5da693..789428bdd4 100644 --- a/docs/tutorials/aws-load-balancer-controller.md +++ b/docs/tutorials/aws-load-balancer-controller.md @@ -137,42 +137,3 @@ spec: In the above example we create a default path that works for any hostname, and make use of the `external-dns.alpha.kubernetes.io/hostname` annotation to create multiple aliases for the resulting ALB. - -## Dualstack ALBs - -AWS [supports][4] both IPv4 and "dualstack" (both IPv4 and IPv6) interfaces for ALBs. -The AWS Load Balancer Controller uses the `alb.ingress.kubernetes.io/ip-address-type` -annotation (which defaults to `ipv4`) to determine this. If this annotation is -set to `dualstack` then ExternalDNS will create two alias records (one A record -and one AAAA record) for each hostname associated with the Ingress object. - -[4]: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#ip-address-type - -Example: - -```yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - alb.ingress.kubernetes.io/scheme: internet-facing - alb.ingress.kubernetes.io/ip-address-type: dualstack - name: echoserver -spec: - ingressClassName: alb - rules: - - host: echoserver.example.org - http: - paths: - - path: / - backend: - service: - name: echoserver - port: - number: 80 - pathType: Prefix -``` - -The above Ingress object will result in the creation of an ALB with a dualstack -interface. ExternalDNS will create both an A `echoserver.example.org` record and -an AAAA record of the same name, that each are aliases for the same ALB. diff --git a/docs/tutorials/kube-ingress-aws.md b/docs/tutorials/kube-ingress-aws.md index 5cf37d4ec9..a56975c629 100644 --- a/docs/tutorials/kube-ingress-aws.md +++ b/docs/tutorials/kube-ingress-aws.md @@ -164,9 +164,9 @@ traffic to skipper which will forward to the echoserver application. If the `--source=ingress` argument is specified, then ExternalDNS will create DNS records based on the hosts specified in ingress objects. The above example would -result in two alias records being created, `echoserver.mycluster.example.org` and -`echoserver.example.org`, which both alias the ALB that is associated with the -Ingress object. +result in four alias records being created: `echoserver.mycluster.example.org` and +`echoserver.example.org`, each domain with an A and AAAA, all aliasing the ALB that +is associated with the Ingress object. Note that the above example makes use of the YAML anchor feature to avoid having to repeat the http section for multiple hosts that use the exact same paths. If @@ -198,43 +198,6 @@ In the above example we create a default path that works for any hostname, and make use of the `external-dns.alpha.kubernetes.io/hostname` annotation to create multiple aliases for the resulting ALB. -## Dualstack ALBs - -AWS [supports](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#ip-address-type) both IPv4 and "dualstack" (both IPv4 and IPv6) interfaces for ALBs. -The Kubernetes Ingress AWS controller supports the `alb.ingress.kubernetes.io/ip-address-type` -annotation (which defaults to `ipv4`) to determine this. If this annotation is -set to `dualstack` then ExternalDNS will create two alias records (one A record -and one AAAA record) for each hostname associated with the Ingress object. - - -Example: - -```yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - alb.ingress.kubernetes.io/ip-address-type: dualstack - name: echoserver -spec: - ingressClassName: skipper - rules: - - host: echoserver.example.org - http: - paths: - - path: / - backend: - service: - name: echoserver - port: - number: 80 - pathType: Prefix -``` - -The above Ingress object will result in the creation of an ALB with a dualstack -interface. ExternalDNS will create both an A `echoserver.example.org` record and -an AAAA record of the same name, that each are aliases for the same ALB. - ## NLBs AWS has @@ -279,8 +242,8 @@ status: - hostname: kube-ing-lb-atedkrlml7iu-1681027139.$region.elb.amazonaws.com ``` -ExternalDNS will create a A-records `echoserver.example.org`, that -use AWS ALIAS record to automatically maintain IP addresses of the NLB. +ExternalDNS will create `echoserver.example.org` A and AAAA alias records +to automatically maintain IP addresses of the NLB. ## RouteGroup (optional) diff --git a/endpoint/labels.go b/endpoint/labels.go index c65333dc6e..ef4d7e9388 100644 --- a/endpoint/labels.go +++ b/endpoint/labels.go @@ -41,9 +41,6 @@ const ( // supposed to be inserted by AWS SD Provider, and parsed into OwnerLabelKey and ResourceLabelKey key by AWS SD Registry AWSSDDescriptionLabel = "aws-sd-description" - // DualstackLabelKey is the name of the label that identifies dualstack endpoints - DualstackLabelKey = "dualstack" - // txtEncryptionNonce label for keep same nonce for same txt records, for prevent different result of encryption for same txt record, it can cause issues for some providers txtEncryptionNonce = "txt-encryption-nonce" ) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 235841f4a5..50c56fa9b3 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -360,8 +360,12 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos if ttl == 0 { ttl = recordTTL } + recordType := aws.StringValue(r.Type) + if recordType == endpoint.RecordTypeA { + recordType = endpoint.RecordTypeCNAME + } ep := endpoint. - NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeCNAME, ttl, aws.StringValue(r.AliasTarget.DNSName)). + NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), recordType, ttl, aws.StringValue(r.AliasTarget.DNSName)). WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", aws.BoolValue(r.AliasTarget.EvaluateTargetHealth))). WithProviderSpecific(providerSpecificAlias, "true") newEndpoints = append(newEndpoints, ep) @@ -611,15 +615,8 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) changes := make(Route53Changes, 0, len(endpoints)) for _, endpoint := range endpoints { - change, dualstack := p.newChange(action, endpoint) + change := p.newChange(action, endpoint) changes = append(changes, change) - if dualstack { - // make a copy of change, modify RRS type to AAAA, then add new change - rrs := *change.ResourceRecordSet - change2 := &Route53Change{Change: route53.Change{Action: change.Action, ResourceRecordSet: &rrs}} - change2.ResourceRecordSet.Type = aws.String(route53.RRTypeAaaa) - changes = append(changes, change2) - } } return changes @@ -631,9 +628,10 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) // Example: CNAME endpoints pointing to ELBs will have a `alias` provider-specific property // added to match the endpoints generated from existing alias records in Route53. func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint { + var additionalEndpoints []*endpoint.Endpoint for _, ep := range endpoints { alias := false - if ep.RecordType != endpoint.RecordTypeCNAME { + if ep.RecordType != endpoint.RecordTypeCNAME && ep.RecordType != endpoint.RecordTypeAAAA { ep.DeleteProviderSpecificProperty(providerSpecificAlias) } else if aliasString, ok := ep.GetProviderSpecificProperty(providerSpecificAlias); ok { alias = aliasString == "true" @@ -661,15 +659,21 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoin } else { ep.DeleteProviderSpecificProperty(providerSpecificEvaluateTargetHealth) } + + if alias { + epAAAA := *ep + epAAAA.RecordType = endpoint.RecordTypeAAAA + additionalEndpoints = append(additionalEndpoints, &epAAAA) + } } - return endpoints + return append(endpoints, additionalEndpoints...) } // newChange returns a route53 Change and a boolean indicating if there should also be a change to a AAAA record // returned Change is based on the given record by the given action, e.g. // action=ChangeActionCreate returns a change for creation of the record and // action=ChangeActionDelete returns a change for deletion of the record. -func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53Change, bool) { +func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) *Route53Change { change := &Route53Change{ Change: route53.Change{ Action: aws.String(action), @@ -678,17 +682,16 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C }, }, } - dualstack := false if targetHostedZone := isAWSAlias(ep); targetHostedZone != "" { evalTargetHealth := p.evaluateTargetHealth if prop, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok { evalTargetHealth = prop == "true" } - // If the endpoint has a Dualstack label, append a change for AAAA record as well. - if val, ok := ep.Labels[endpoint.DualstackLabelKey]; ok { - dualstack = val == "true" + if ep.RecordType == endpoint.RecordTypeCNAME { + change.ResourceRecordSet.Type = aws.String(route53.RRTypeA) + } else { + change.ResourceRecordSet.Type = aws.String(ep.RecordType) } - change.ResourceRecordSet.Type = aws.String(route53.RRTypeA) change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{ DNSName: aws.String(ep.Targets[0]), HostedZoneId: aws.String(cleanZoneID(targetHostedZone)), @@ -758,7 +761,7 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C change.OwnedRecord = ownedRecord } - return change, dualstack + return change } // searches for `changes` that are contained in `queue` and returns the `changes` separated by whether they were found in the queue (`foundChanges`) or not (`notFoundChanges`) @@ -965,8 +968,11 @@ func useAlias(ep *endpoint.Endpoint, preferCNAME bool) bool { // isAWSAlias determines if a given endpoint is supposed to create an AWS Alias record // and (if so) returns the target hosted zone ID func isAWSAlias(ep *endpoint.Endpoint) string { + if ep.RecordType != endpoint.RecordTypeCNAME && ep.RecordType != endpoint.RecordTypeAAAA { + return "" + } isAlias, exists := ep.GetProviderSpecificProperty(providerSpecificAlias) - if exists && isAlias == "true" && ep.RecordType == endpoint.RecordTypeCNAME && len(ep.Targets) > 0 { + if exists && isAlias == "true" && len(ep.Targets) > 0 { // alias records can only point to canonical hosted zones (e.g. to ELBs) or other records in the same zone if hostedZoneID, ok := ep.GetProviderSpecificProperty(providerSpecificTargetHostedZone); ok { diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index cce21e66a8..c8c0430230 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -365,6 +365,15 @@ func TestAWSRecords(t *testing.T) { HostedZoneId: aws.String("Z215JYRZR1TBD5"), }, }, + { + Name: aws.String("list-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("bar.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(false), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -499,6 +508,7 @@ func TestAWSRecords(t *testing.T) { 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.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "bar.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "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"), @@ -535,9 +545,12 @@ func TestAWSAdjustEndpoints(t *testing.T) { endpoint.NewEndpoint("a-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), endpoint.NewEndpoint("cname-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.example.com").WithProviderSpecific(providerSpecificAlias, "false"), endpoint.NewEndpointWithTTL("cname-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, 300, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), + endpoint.NewEndpointWithTTL("cname-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, 300, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), endpoint.NewEndpoint("cname-test-elb.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("cname-test-elb.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("cname-test-elb-no-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "false"), endpoint.NewEndpoint("cname-test-elb-no-eth.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), // eth = evaluate target health + endpoint.NewEndpoint("cname-test-elb-no-eth.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), // eth = evaluate target health }) } @@ -551,7 +564,9 @@ func TestAWSCreateRecords(t *testing.T) { endpoint.NewEndpointWithTTL("create-test-custom-ttl.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, customTTL, "172.17.0.1"), endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.example.com"), endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("create-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("create-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("create-test-aaaa-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("create-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), endpoint.NewEndpoint("create-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, "10 mailhost1.example.com", "20 mailhost2.example.com"), } @@ -588,6 +603,15 @@ func TestAWSCreateRecords(t *testing.T) { HostedZoneId: aws.String("Z215JYRZR1TBD5"), }, }, + { + Name: aws.String("create-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("create-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -617,6 +641,15 @@ func TestAWSCreateRecords(t *testing.T) { HostedZoneId: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."), }, }, + { + Name: aws.String("create-test-aaaa-alias.zone-2.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("alias-target.zone-2.ext-dns-test-2.teapot.zalan.do."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."), + }, + }, }) } @@ -762,6 +795,15 @@ func TestAWSDeleteRecords(t *testing.T) { HostedZoneId: aws.String("Z215JYRZR1TBD5"), }, }, + { + Name: aws.String("delete-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("delete-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -771,6 +813,15 @@ func TestAWSDeleteRecords(t *testing.T) { HostedZoneId: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."), }, }, + { + Name: aws.String("delete-test-aaaa-alias.zone-2.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("zone-2.ext-dns-test-2.teapot.zalan.do."), + }, + }, { Name: aws.String("delete-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -792,7 +843,9 @@ func TestAWSDeleteRecords(t *testing.T) { 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").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), 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").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("delete-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("delete-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "delete-test.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificTargetHostedZone, "/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do."), + endpoint.NewEndpoint("delete-test-aaaa-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "delete-test.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificTargetHostedZone, "/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do.").WithProviderSpecific(providerSpecificAlias, "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"), endpoint.NewEndpoint("delete-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, "10 mailhost1.foo.elb.amazonaws.com", "20 mailhost2.foo.elb.amazonaws.com"), }, @@ -858,6 +911,15 @@ func TestAWSApplyChanges(t *testing.T) { HostedZoneId: aws.String("Z215JYRZR1TBD5"), }, }, + { + Name: aws.String("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeCname), @@ -951,6 +1013,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.4.4"), endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com"), endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com"), + endpoint.NewEndpoint("create-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "bar.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("create-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), endpoint.NewEndpoint("create-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, "10 mailhost1.foo.elb.amazonaws.com"), } @@ -960,6 +1023,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.4.4"), endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.1.1.1"), endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), @@ -975,6 +1039,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "4.3.2.1"), endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "my-internal-host.example.com"), + endpoint.NewEndpoint("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "bar.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4", "4.3.2.1"), @@ -1034,12 +1099,30 @@ func TestAWSApplyChanges(t *testing.T) { HostedZoneId: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."), }, }, + { + Name: aws.String("create-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("bar.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."), + }, + }, { Name: aws.String("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeCname), TTL: aws.Int64(recordTTL), ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("my-internal-host.example.com")}}, }, + { + Name: aws.String("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("bar.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeCname), @@ -1611,7 +1694,7 @@ func validateEndpoints(t *testing.T, provider *AWSProvider, endpoints []*endpoin assert.True(t, testutils.SameEndpoints(endpoints, expected), "actual and expected endpoints don't match. %+v:%+v", endpoints, expected) normalized := provider.AdjustEndpoints(endpoints) - assert.True(t, testutils.SameEndpoints(normalized, expected), "actual and normalized endpoints don't match. %+v:%+v", endpoints, normalized) + assert.True(t, testutils.SameEndpoints(normalized[:len(expected)], expected), "actual and normalized endpoints don't match. %+v:%+v", endpoints, normalized) } func validateAWSZones(t *testing.T, zones map[string]*route53.HostedZone, expected map[string]*route53.HostedZone) { @@ -1676,7 +1759,7 @@ func TestAWSCreateRecordsWithALIAS(t *testing.T) { } { provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, nil) - // Test dualstack and ipv4 load balancer targets + // Test load balancer targets records := []*endpoint.Endpoint{ { DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", @@ -1694,9 +1777,9 @@ func TestAWSCreateRecordsWithALIAS(t *testing.T) { }, }, { - DNSName: "create-test-dualstack.zone-1.ext-dns-test-2.teapot.zalan.do", - Targets: endpoint.Targets{"bar.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.RecordTypeAAAA, ProviderSpecific: endpoint.ProviderSpecific{ endpoint.ProviderSpecificProperty{ Name: providerSpecificAlias, @@ -1706,8 +1789,11 @@ func TestAWSCreateRecordsWithALIAS(t *testing.T) { Name: providerSpecificEvaluateTargetHealth, Value: key, }, + endpoint.ProviderSpecificProperty{ + Name: providerSpecificAlias, + Value: "true", + }, }, - Labels: map[string]string{endpoint.DualstackLabelKey: "true"}, }, } @@ -1729,20 +1815,11 @@ func TestAWSCreateRecordsWithALIAS(t *testing.T) { }, { AliasTarget: &route53.AliasTarget{ - DNSName: aws.String("bar.eu-central-1.elb.amazonaws.com."), - EvaluateTargetHealth: aws.Bool(evaluateTargetHealth), - HostedZoneId: aws.String("Z215JYRZR1TBD5"), - }, - Name: aws.String("create-test-dualstack.zone-1.ext-dns-test-2.teapot.zalan.do."), - Type: aws.String(route53.RRTypeA), - }, - { - AliasTarget: &route53.AliasTarget{ - DNSName: aws.String("bar.eu-central-1.elb.amazonaws.com."), + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), EvaluateTargetHealth: aws.Bool(evaluateTargetHealth), HostedZoneId: aws.String("Z215JYRZR1TBD5"), }, - Name: aws.String("create-test-dualstack.zone-1.ext-dns-test-2.teapot.zalan.do."), + Name: aws.String("create-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeAaaa), }, }) @@ -1776,10 +1853,14 @@ func TestAWSisAWSAlias(t *testing.T) { alias bool hz string }{ - {"foo.example.org", endpoint.RecordTypeCNAME, false, ""}, // normal CNAME - {"bar.eu-central-1.elb.amazonaws.com", endpoint.RecordTypeCNAME, true, "Z215JYRZR1TBD5"}, // pointing to ELB DNS name - {"foobar.example.org", endpoint.RecordTypeCNAME, true, "Z1234567890ABC"}, // HZID retrieved by Route53 - {"baz.example.org", endpoint.RecordTypeCNAME, true, sameZoneAlias}, // record to be created + {"foo.example.org", endpoint.RecordTypeCNAME, false, ""}, // normal CNAME + {"foo-aaaa.example.org", endpoint.RecordTypeAAAA, false, ""}, // normal CNAME + {"bar.eu-central-1.elb.amazonaws.com", endpoint.RecordTypeCNAME, true, "Z215JYRZR1TBD5"}, // pointing to ELB DNS name + {"bar-aaaa.eu-central-1.elb.amazonaws.com", endpoint.RecordTypeAAAA, true, "Z215JYRZR1TBD5"}, // pointing to ELB DNS name + {"foobar.example.org", endpoint.RecordTypeCNAME, true, "Z1234567890ABC"}, // HZID retrieved by Route53 + {"foobar-aaaa.example.org", endpoint.RecordTypeAAAA, true, "Z1234567890ABC"}, // HZID retrieved by Route53 + {"baz.example.org", endpoint.RecordTypeCNAME, true, sameZoneAlias}, // record to be created + {"baz-aaaa.example.org", endpoint.RecordTypeAAAA, true, sameZoneAlias}, // record to be created } { ep := &endpoint.Endpoint{ Targets: endpoint.Targets{tc.target}, diff --git a/source/ingress.go b/source/ingress.go index af7a9dc990..9b8ee014c2 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -37,11 +37,6 @@ import ( ) const ( - // ALBDualstackAnnotationKey is the annotation used for determining if an ALB ingress is dualstack - ALBDualstackAnnotationKey = "alb.ingress.kubernetes.io/ip-address-type" - // ALBDualstackAnnotationValue is the value of the ALB dualstack annotation that indicates it is dualstack - ALBDualstackAnnotationValue = "dualstack" - // Possible values for the ingress-hostname-source annotation IngressHostnameSourceAnnotationOnlyValue = "annotation-only" IngressHostnameSourceDefinedHostsOnlyValue = "defined-hosts-only" @@ -176,7 +171,6 @@ func (sc *ingressSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e log.Debugf("Endpoints generated from ingress: %s/%s: %v", ing.Namespace, ing.Name, ingEndpoints) sc.setResourceLabel(ing, ingEndpoints) - sc.setDualstackLabel(ing, ingEndpoints) endpoints = append(endpoints, ingEndpoints...) } @@ -286,16 +280,6 @@ func (sc *ingressSource) setResourceLabel(ingress *networkv1.Ingress, endpoints } } -func (sc *ingressSource) setDualstackLabel(ingress *networkv1.Ingress, endpoints []*endpoint.Endpoint) { - val, ok := ingress.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to ingress %s/%s.", ingress.Namespace, ingress.Name) - for _, ep := range endpoints { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} - // endpointsFromIngress extracts the endpoints from ingress object func endpointsFromIngress(ing *networkv1.Ingress, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool, ignoreIngressRulesSpec bool) []*endpoint.Endpoint { ttl, err := getTTLFromAnnotations(ing.Annotations) diff --git a/source/ingress_test.go b/source/ingress_test.go index 2be3eddfd0..919d6c8d88 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -44,12 +44,11 @@ func (suite *IngressSuite) SetupTest() { fakeClient := fake.NewSimpleClientset() suite.fooWithTargets = (fakeIngress{ - name: "foo-with-targets", - namespace: "default", - dnsnames: []string{"foo"}, - ips: []string{"8.8.8.8"}, - hostnames: []string{"v1"}, - annotations: map[string]string{ALBDualstackAnnotationKey: ALBDualstackAnnotationValue}, + name: "foo-with-targets", + namespace: "default", + dnsnames: []string{"foo"}, + ips: []string{"8.8.8.8"}, + hostnames: []string{"v1"}, }).Ingress() _, err := fakeClient.NetworkingV1().Ingresses(suite.fooWithTargets.Namespace).Create(context.Background(), suite.fooWithTargets, metav1.CreateOptions{}) suite.NoError(err, "should succeed") @@ -77,13 +76,6 @@ func (suite *IngressSuite) TestResourceLabelIsSet() { } } -func (suite *IngressSuite) TestDualstackLabelIsSet() { - endpoints, _ := suite.sc.Endpoints(context.Background()) - for _, ep := range endpoints { - suite.Equal("true", ep.Labels[endpoint.DualstackLabelKey], "should set dualstack label to true") - } -} - func TestIngress(t *testing.T) { t.Parallel() diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go index 6dac0a60aa..2a2091b267 100644 --- a/source/kong_tcpingress.go +++ b/source/kong_tcpingress.go @@ -147,7 +147,6 @@ func (sc *kongTCPIngressSource) Endpoints(ctx context.Context) ([]*endpoint.Endp log.Debugf("Endpoints generated from TCPIngress: %s: %v", fullname, ingressEndpoints) sc.setResourceLabel(tcpIngress, ingressEndpoints) - sc.setDualstackLabel(tcpIngress, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -195,16 +194,6 @@ func (sc *kongTCPIngressSource) setResourceLabel(tcpIngress *TCPIngress, endpoin } } -func (sc *kongTCPIngressSource) setDualstackLabel(tcpIngress *TCPIngress, endpoints []*endpoint.Endpoint) { - val, ok := tcpIngress.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to TCPIngress %s/%s.", tcpIngress.Namespace, tcpIngress.Name) - for _, ep := range endpoints { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} - // endpointsFromTCPIngress extracts the endpoints from a TCPIngress object func (sc *kongTCPIngressSource) endpointsFromTCPIngress(tcpIngress *TCPIngress, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { var endpoints []*endpoint.Endpoint diff --git a/source/skipper_routegroup.go b/source/skipper_routegroup.go index 252f0b8eb9..16840378df 100644 --- a/source/skipper_routegroup.go +++ b/source/skipper_routegroup.go @@ -280,7 +280,6 @@ func (sc *routeGroupSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint log.Debugf("Endpoints generated from ingress: %s/%s: %v", rg.Metadata.Namespace, rg.Metadata.Name, eps) sc.setRouteGroupResourceLabel(rg, eps) - sc.setRouteGroupDualstackLabel(rg, eps) endpoints = append(endpoints, eps...) } @@ -328,16 +327,6 @@ func (sc *routeGroupSource) setRouteGroupResourceLabel(rg *routeGroup, eps []*en } } -func (sc *routeGroupSource) setRouteGroupDualstackLabel(rg *routeGroup, eps []*endpoint.Endpoint) { - val, ok := rg.Metadata.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to routegroup %s/%s.", rg.Metadata.Namespace, rg.Metadata.Name) - for _, ep := range eps { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} - // annotation logic ported from source/ingress.go without Spec.TLS part, because it'S not supported in RouteGroup func (sc *routeGroupSource) endpointsFromRouteGroup(rg *routeGroup) []*endpoint.Endpoint { endpoints := []*endpoint.Endpoint{} diff --git a/source/skipper_routegroup_test.go b/source/skipper_routegroup_test.go index 9b4c325a58..28b9214b81 100644 --- a/source/skipper_routegroup_test.go +++ b/source/skipper_routegroup_test.go @@ -787,37 +787,6 @@ func TestResourceLabelIsSet(t *testing.T) { } } -func TestDualstackLabelIsSet(t *testing.T) { - source := &routeGroupSource{ - cli: &fakeRouteGroupClient{ - rg: &routeGroupList{ - Items: []*routeGroup{ - createTestRouteGroup( - "namespace1", - "rg1", - map[string]string{ - ALBDualstackAnnotationKey: ALBDualstackAnnotationValue, - }, - []string{"rg1.k8s.example"}, - []routeGroupLoadBalancer{ - { - Hostname: "lb.example.org", - }, - }, - ), - }, - }, - }, - } - - got, _ := source.Endpoints(context.Background()) - for _, ep := range got { - if v, ok := ep.Labels[endpoint.DualstackLabelKey]; !ok || v != "true" { - t.Errorf("Failed to set resource label on ep %v", ep) - } - } -} - func TestParseTemplate(t *testing.T) { for _, tt := range []struct { name string diff --git a/source/traefik_proxy.go b/source/traefik_proxy.go index 38bc75b3ee..f96dc06367 100644 --- a/source/traefik_proxy.go +++ b/source/traefik_proxy.go @@ -251,7 +251,6 @@ func (ts *traefikSource) ingressRouteEndpoints() ([]*endpoint.Endpoint, error) { log.Debugf("Endpoints generated from IngressRoute: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRoute(ingressRoute, ingressEndpoints) - ts.setDualstackLabelIngressRoute(ingressRoute, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -305,7 +304,6 @@ func (ts *traefikSource) ingressRouteTCPEndpoints() ([]*endpoint.Endpoint, error log.Debugf("Endpoints generated from IngressRouteTCP: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRouteTCP(ingressRouteTCP, ingressEndpoints) - ts.setDualstackLabelIngressRouteTCP(ingressRouteTCP, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -359,7 +357,6 @@ func (ts *traefikSource) ingressRouteUDPEndpoints() ([]*endpoint.Endpoint, error log.Debugf("Endpoints generated from IngressRouteUDP: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRouteUDP(ingressRouteUDP, ingressEndpoints) - ts.setDualstackLabelIngressRouteUDP(ingressRouteUDP, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -413,7 +410,6 @@ func (ts *traefikSource) oldIngressRouteEndpoints() ([]*endpoint.Endpoint, error log.Debugf("Endpoints generated from IngressRoute: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRoute(ingressRoute, ingressEndpoints) - ts.setDualstackLabelIngressRoute(ingressRoute, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -467,7 +463,6 @@ func (ts *traefikSource) oldIngressRouteTCPEndpoints() ([]*endpoint.Endpoint, er log.Debugf("Endpoints generated from IngressRouteTCP: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRouteTCP(ingressRouteTCP, ingressEndpoints) - ts.setDualstackLabelIngressRouteTCP(ingressRouteTCP, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -521,7 +516,6 @@ func (ts *traefikSource) oldIngressRouteUDPEndpoints() ([]*endpoint.Endpoint, er log.Debugf("Endpoints generated from IngressRouteUDP: %s: %v", fullname, ingressEndpoints) ts.setResourceLabelIngressRouteUDP(ingressRouteUDP, ingressEndpoints) - ts.setDualstackLabelIngressRouteUDP(ingressRouteUDP, ingressEndpoints) endpoints = append(endpoints, ingressEndpoints...) } @@ -637,34 +631,6 @@ func (ts *traefikSource) setResourceLabelIngressRouteUDP(ingressroute *IngressRo } } -func (ts *traefikSource) setDualstackLabelIngressRoute(ingressRoute *IngressRoute, endpoints []*endpoint.Endpoint) { - val, ok := ingressRoute.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to IngressRoute %s/%s.", ingressRoute.Namespace, ingressRoute.Name) - for _, ep := range endpoints { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} -func (ts *traefikSource) setDualstackLabelIngressRouteTCP(ingressRoute *IngressRouteTCP, endpoints []*endpoint.Endpoint) { - val, ok := ingressRoute.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to IngressRouteTCP %s/%s.", ingressRoute.Namespace, ingressRoute.Name) - for _, ep := range endpoints { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} -func (ts *traefikSource) setDualstackLabelIngressRouteUDP(ingressRoute *IngressRouteUDP, endpoints []*endpoint.Endpoint) { - val, ok := ingressRoute.Annotations[ALBDualstackAnnotationKey] - if ok && val == ALBDualstackAnnotationValue { - log.Debugf("Adding dualstack label to IngressRouteUDP %s/%s.", ingressRoute.Namespace, ingressRoute.Name) - for _, ep := range endpoints { - ep.Labels[endpoint.DualstackLabelKey] = "true" - } - } -} - // endpointsFromIngressRoute extracts the endpoints from a IngressRoute object func (ts *traefikSource) endpointsFromIngressRoute(ingressRoute *IngressRoute, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { var endpoints []*endpoint.Endpoint From eef19a24b9951a555fa8f8245b9558f3e5fb17d5 Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Sat, 13 May 2023 09:46:13 -0700 Subject: [PATCH 2/3] Add more route53 alias update tests --- provider/aws/aws_test.go | 81 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index c8c0430230..2cf60b252f 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -897,11 +897,35 @@ func TestAWSApplyChanges(t *testing.T) { ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { - Name: aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), + Name: aws.String("update-test-a-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), TTL: aws.Int64(recordTTL), ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("1.1.1.1")}}, }, + { + Name: aws.String("update-test-aaaa-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + TTL: aws.Int64(recordTTL), + ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("2001:DB8::1")}}, + }, + { + Name: aws.String("update-test-alias-to-a.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeA), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, + { + Name: aws.String("update-test-alias-to-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -964,6 +988,17 @@ func TestAWSApplyChanges(t *testing.T) { SetIdentifier: aws.String("weighted-to-simple"), Weight: aws.Int64(10), }, + { + Name: aws.String("weighted-to-simple-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeA), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + SetIdentifier: aws.String("weighted-to-simple-alias"), + Weight: aws.Int64(10), + }, { Name: aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), @@ -1021,13 +1056,17 @@ func TestAWSApplyChanges(t *testing.T) { currentRecords := []*endpoint.Endpoint{ endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.4.4"), - endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.1.1.1"), + endpoint.NewEndpoint("update-test-a-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.1.1.1"), + endpoint.NewEndpoint("update-test-aaaa-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "2001:DB8::1"), + endpoint.NewEndpoint("update-test-alias-to-a.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("update-test-alias-to-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), 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("weighted-to-simple-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithSetIdentifier("weighted-to-simple-alias").WithProviderSpecific(providerSpecificWeight, "10").WithProviderSpecific(providerSpecificAlias, "true"), 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"), @@ -1037,13 +1076,17 @@ func TestAWSApplyChanges(t *testing.T) { updatedRecords := []*endpoint.Endpoint{ endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "4.3.2.1"), - endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("update-test-a-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("update-test-aaaa-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "bar.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("update-test-alias-to-a.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.1.1.1"), + endpoint.NewEndpoint("update-test-alias-to-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "2001:DB8::1"), endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "my-internal-host.example.com"), endpoint.NewEndpoint("update-test-aaaa-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, "bar.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4", "4.3.2.1"), endpoint.NewEndpoint("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), + endpoint.NewEndpoint("weighted-to-simple-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), 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"), @@ -1091,7 +1134,7 @@ func TestAWSApplyChanges(t *testing.T) { ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { - Name: aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), + Name: aws.String("update-test-a-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), AliasTarget: &route53.AliasTarget{ DNSName: aws.String("foo.elb.amazonaws.com."), @@ -1108,6 +1151,27 @@ func TestAWSApplyChanges(t *testing.T) { HostedZoneId: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."), }, }, + { + Name: aws.String("update-test-aaaa-to-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("bar.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("zone-1.ext-dns-test-2.teapot.zalan.do."), + }, + }, + { + Name: aws.String("update-test-alias-to-a.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeA), + TTL: aws.Int64(recordTTL), + ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("1.1.1.1")}}, + }, + { + Name: aws.String("update-test-alias-to-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeAaaa), + TTL: aws.Int64(recordTTL), + ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("2001:DB8::1")}}, + }, { Name: aws.String("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeCname), @@ -1153,6 +1217,15 @@ func TestAWSApplyChanges(t *testing.T) { TTL: aws.Int64(recordTTL), ResourceRecords: []*route53.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, + { + Name: aws.String("weighted-to-simple-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), + Type: aws.String(route53.RRTypeA), + AliasTarget: &route53.AliasTarget{ + DNSName: aws.String("foo.eu-central-1.elb.amazonaws.com."), + EvaluateTargetHealth: aws.Bool(true), + HostedZoneId: aws.String("Z215JYRZR1TBD5"), + }, + }, { Name: aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: aws.String(route53.RRTypeA), From 4dcce15b7f506b2eb00f062cd183baeba49a1f62 Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Wed, 28 Jun 2023 17:22:38 -0700 Subject: [PATCH 3/3] Update additional documentation --- docs/tutorials/aws-load-balancer-controller.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/aws-load-balancer-controller.md b/docs/tutorials/aws-load-balancer-controller.md index 789428bdd4..f6f2fa641d 100644 --- a/docs/tutorials/aws-load-balancer-controller.md +++ b/docs/tutorials/aws-load-balancer-controller.md @@ -103,9 +103,9 @@ traffic to the echoserver application. If the `source=ingress` argument is specified, then ExternalDNS will create DNS records based on the hosts specified in ingress objects. The above example would -result in two alias records being created, `echoserver.mycluster.example.org` and -`echoserver.example.org`, which both alias the ALB that is associated with the -Ingress object. +result in four alias records being created, an A and AAAA for each of `echoserver.mycluster.example.org` and +`echoserver.example.org`, which all alias the ALB that is associated with the +Ingress object. As the ALB is IPv4-only, the AAAA alias records have no effect. Note that the above example makes use of the YAML anchor feature to avoid having to repeat the http section for multiple hosts that use the exact same paths. If