mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 09:06:58 +02:00
Refactor AWS provider to aws-sdk-go-v2
Signed-off-by: Michael Shen <mishen@umich.edu>
This commit is contained in:
parent
c4a18a9cb6
commit
5ec37e0699
1
go.mod
1
go.mod
@ -22,6 +22,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.27
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.27
|
||||||
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10
|
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.10
|
||||||
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4
|
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.4
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3
|
||||||
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3
|
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3
|
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3
|
||||||
github.com/bodgit/tsig v1.2.2
|
github.com/bodgit/tsig v1.2.2
|
||||||
|
2
go.sum
2
go.sum
@ -145,6 +145,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16 h1:lhAX
|
|||||||
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16/go.mod h1:AblAlCwvi7Q/SFowvckgN+8M3uFPlopSYeLlbNDArhA=
|
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.16/go.mod h1:AblAlCwvi7Q/SFowvckgN+8M3uFPlopSYeLlbNDArhA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 h1:MmLCRqP4U4Cw9gJ4bNrCG0mWqEtBlmAVleyelcHARMU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3/go.mod h1:AMPjK2YnRh0YgOID3PqhJA1BRNfXDfGOnSsKHtAe8yA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3 h1:EthA93BNgTnk36FoI9DCKtv4S0m63WzdGDYlBp/CvHQ=
|
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3 h1:EthA93BNgTnk36FoI9DCKtv4S0m63WzdGDYlBp/CvHQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3/go.mod h1:4xh/h0pevPhBkA4b2iYosZaqrThccxFREQxiGuZpJlc=
|
github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.3/go.mod h1:4xh/h0pevPhBkA4b2iYosZaqrThccxFREQxiGuZpJlc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
|
||||||
|
10
main.go
10
main.go
@ -26,8 +26,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
|
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||||
sd "github.com/aws/aws-sdk-go-v2/service/servicediscovery"
|
sd "github.com/aws/aws-sdk-go-v2/service/servicediscovery"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -205,10 +205,10 @@ func main() {
|
|||||||
case "alibabacloud":
|
case "alibabacloud":
|
||||||
p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
|
p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
|
||||||
case "aws":
|
case "aws":
|
||||||
sessions := aws.CreateSessions(cfg)
|
configs := aws.CreateV2Configs(cfg)
|
||||||
clients := make(map[string]aws.Route53API, len(sessions))
|
clients := make(map[string]aws.Route53API, len(configs))
|
||||||
for profile, session := range sessions {
|
for profile, config := range configs {
|
||||||
clients[profile] = route53.New(session)
|
clients[profile] = route53.NewFromConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err = aws.NewAWSProvider(
|
p, err = aws.NewAWSProvider(
|
||||||
|
@ -25,10 +25,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"sigs.k8s.io/external-dns/endpoint"
|
"sigs.k8s.io/external-dns/endpoint"
|
||||||
@ -41,11 +40,11 @@ const (
|
|||||||
recordTTL = 300
|
recordTTL = 300
|
||||||
// From the experiments, it seems that the default MaxItems applied is 100,
|
// From the experiments, it seems that the default MaxItems applied is 100,
|
||||||
// and that, on the server side, there is a hard limit of 300 elements per page.
|
// and that, on the server side, there is a hard limit of 300 elements per page.
|
||||||
// After a discussion with AWS representants, clients should accept
|
// After a discussion with AWS representatives, clients should accept
|
||||||
// when less items are returned, and still paginate accordingly.
|
// when fewer items are returned, and still paginate accordingly.
|
||||||
// As we are using the standard AWS client, this should already be compliant.
|
// As we are using the standard AWS client, this should already be compliant.
|
||||||
// Hence, ifever AWS decides to raise this limit, we will automatically reduce the pressure on rate limits
|
// Hence, if AWS ever decides to raise this limit, we will automatically reduce the pressure on rate limits
|
||||||
route53PageSize = "300"
|
route53PageSize int32 = 300
|
||||||
// providerSpecificAlias specifies whether a CNAME endpoint maps to an AWS ALIAS record.
|
// providerSpecificAlias specifies whether a CNAME endpoint maps to an AWS ALIAS record.
|
||||||
providerSpecificAlias = "alias"
|
providerSpecificAlias = "alias"
|
||||||
providerSpecificTargetHostedZone = "aws/target-hosted-zone"
|
providerSpecificTargetHostedZone = "aws/target-hosted-zone"
|
||||||
@ -199,16 +198,16 @@ var canonicalHostedZones = map[string]string{
|
|||||||
// Route53API is the subset of the AWS Route53 API that we actually use. Add methods as required. Signatures must match exactly.
|
// Route53API is the subset of the AWS Route53 API that we actually use. Add methods as required. Signatures must match exactly.
|
||||||
// mostly taken from: https://github.com/kubernetes/kubernetes/blob/853167624edb6bc0cfdcdfb88e746e178f5db36c/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go
|
// mostly taken from: https://github.com/kubernetes/kubernetes/blob/853167624edb6bc0cfdcdfb88e746e178f5db36c/federation/pkg/dnsprovider/providers/aws/route53/stubs/route53api.go
|
||||||
type Route53API interface {
|
type Route53API interface {
|
||||||
ListResourceRecordSetsPagesWithContext(ctx context.Context, input *route53.ListResourceRecordSetsInput, fn func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool), opts ...request.Option) error
|
ListResourceRecordSets(ctx context.Context, input *route53.ListResourceRecordSetsInput, optFns ...func(options *route53.Options)) (*route53.ListResourceRecordSetsOutput, error)
|
||||||
ChangeResourceRecordSetsWithContext(ctx context.Context, input *route53.ChangeResourceRecordSetsInput, opts ...request.Option) (*route53.ChangeResourceRecordSetsOutput, error)
|
ChangeResourceRecordSets(ctx context.Context, input *route53.ChangeResourceRecordSetsInput, optFns ...func(options *route53.Options)) (*route53.ChangeResourceRecordSetsOutput, error)
|
||||||
CreateHostedZoneWithContext(ctx context.Context, input *route53.CreateHostedZoneInput, opts ...request.Option) (*route53.CreateHostedZoneOutput, error)
|
CreateHostedZone(ctx context.Context, input *route53.CreateHostedZoneInput, optFns ...func(*route53.Options)) (*route53.CreateHostedZoneOutput, error)
|
||||||
ListHostedZonesPagesWithContext(ctx context.Context, input *route53.ListHostedZonesInput, fn func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool), opts ...request.Option) error
|
ListHostedZones(ctx context.Context, input *route53.ListHostedZonesInput, optFns ...func(options *route53.Options)) (*route53.ListHostedZonesOutput, error)
|
||||||
ListTagsForResourceWithContext(ctx context.Context, input *route53.ListTagsForResourceInput, opts ...request.Option) (*route53.ListTagsForResourceOutput, error)
|
ListTagsForResource(ctx context.Context, input *route53.ListTagsForResourceInput, optFns ...func(options *route53.Options)) (*route53.ListTagsForResourceOutput, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrapper to handle ownership relation throughout the provider implementation
|
// wrapper to handle ownership relation throughout the provider implementation
|
||||||
type Route53Change struct {
|
type Route53Change struct {
|
||||||
route53.Change
|
route53types.Change
|
||||||
OwnedRecord string
|
OwnedRecord string
|
||||||
sizeBytes int
|
sizeBytes int
|
||||||
sizeValues int
|
sizeValues int
|
||||||
@ -218,13 +217,13 @@ type Route53Changes []*Route53Change
|
|||||||
|
|
||||||
type profiledZone struct {
|
type profiledZone struct {
|
||||||
profile string
|
profile string
|
||||||
zone *route53.HostedZone
|
zone *route53types.HostedZone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs Route53Changes) Route53Changes() []*route53.Change {
|
func (cs Route53Changes) Route53Changes() []route53types.Change {
|
||||||
ret := []*route53.Change{}
|
ret := []route53types.Change{}
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
ret = append(ret, &c.Change)
|
ret = append(ret, c.Change)
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@ -253,7 +252,7 @@ type AWSProvider struct {
|
|||||||
zoneTypeFilter provider.ZoneTypeFilter
|
zoneTypeFilter provider.ZoneTypeFilter
|
||||||
// filter hosted zones by tags
|
// filter hosted zones by tags
|
||||||
zoneTagFilter provider.ZoneTagFilter
|
zoneTagFilter provider.ZoneTagFilter
|
||||||
// extend filter for sub-domains in the zone (e.g. first.us-east-1.example.com)
|
// extend filter for subdomains in the zone (e.g. first.us-east-1.example.com)
|
||||||
zoneMatchParent bool
|
zoneMatchParent bool
|
||||||
preferCNAME bool
|
preferCNAME bool
|
||||||
zonesCache *zonesListCache
|
zonesCache *zonesListCache
|
||||||
@ -302,13 +301,13 @@ func NewAWSProvider(awsConfig AWSConfig, clients map[string]Route53API) (*AWSPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Zones returns the list of hosted zones.
|
// Zones returns the list of hosted zones.
|
||||||
func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53.HostedZone, error) {
|
func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53types.HostedZone, error) {
|
||||||
zones, err := p.zones(ctx)
|
zones, err := p.zones(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make(map[string]*route53.HostedZone, len(zones))
|
result := make(map[string]*route53types.HostedZone, len(zones))
|
||||||
for id, zone := range zones {
|
for id, zone := range zones {
|
||||||
result[id] = zone.zone
|
result[id] = zone.zone
|
||||||
}
|
}
|
||||||
@ -324,61 +323,57 @@ func (p *AWSProvider) zones(ctx context.Context) (map[string]*profiledZone, erro
|
|||||||
log.Debug("Refreshing zones list cache")
|
log.Debug("Refreshing zones list cache")
|
||||||
|
|
||||||
zones := make(map[string]*profiledZone)
|
zones := make(map[string]*profiledZone)
|
||||||
var profile string
|
|
||||||
var tagErr error
|
|
||||||
f := func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool) {
|
|
||||||
for _, zone := range resp.HostedZones {
|
|
||||||
if !p.zoneIDFilter.Match(aws.StringValue(zone.Id)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !p.zoneTypeFilter.Match(zone) {
|
for profile, client := range p.clients {
|
||||||
continue
|
var tagErr error
|
||||||
}
|
paginator := route53.NewListHostedZonesPaginator(client, &route53.ListHostedZonesInput{})
|
||||||
|
|
||||||
if !p.domainFilter.Match(aws.StringValue(zone.Name)) {
|
for paginator.HasMorePages() {
|
||||||
if !p.zoneMatchParent {
|
resp, err := paginator.NextPage(ctx)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
var te *route53types.ThrottlingException
|
||||||
if !p.domainFilter.MatchParent(aws.StringValue(zone.Name)) {
|
if errors.As(err, &te) {
|
||||||
continue
|
log.Infof("Skipping AWS profile %q due to provider side throttling: %v", profile, te.ErrorMessage())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only fetch tags if a tag filter was specified
|
|
||||||
if !p.zoneTagFilter.IsEmpty() {
|
|
||||||
tags, err := p.tagsForZone(ctx, *zone.Id, profile)
|
|
||||||
if err != nil {
|
|
||||||
tagErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !p.zoneTagFilter.Match(tags) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zones[aws.StringValue(zone.Id)] = &profiledZone{
|
|
||||||
profile: profile,
|
|
||||||
zone: zone,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for p, client := range p.clients {
|
|
||||||
profile = p
|
|
||||||
err := client.ListHostedZonesPagesWithContext(ctx, &route53.ListHostedZonesInput{}, f)
|
|
||||||
if err != nil {
|
|
||||||
var awsErr awserr.Error
|
|
||||||
if errors.As(err, &awsErr) {
|
|
||||||
if awsErr.Code() == route53.ErrCodeThrottlingException {
|
|
||||||
log.Warnf("Skipping AWS profile %q due to provider side throttling: %v", profile, awsErr.Message())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// nothing to do here. Falling through to general error handling
|
// nothing to do here. Falling through to general error handling
|
||||||
|
return nil, provider.NewSoftError(fmt.Errorf("failed to list hosted zones: %w", err))
|
||||||
|
}
|
||||||
|
for _, zone := range resp.HostedZones {
|
||||||
|
if !p.zoneIDFilter.Match(*zone.Id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.zoneTypeFilter.Match(zone) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.domainFilter.Match(*zone.Name) {
|
||||||
|
if !p.zoneMatchParent {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !p.domainFilter.MatchParent(*zone.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only fetch tags if a tag filter was specified
|
||||||
|
if !p.zoneTagFilter.IsEmpty() {
|
||||||
|
tags, err := p.tagsForZone(ctx, *zone.Id, profile)
|
||||||
|
if err != nil {
|
||||||
|
tagErr = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !p.zoneTagFilter.Match(tags) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zones[*zone.Id] = &profiledZone{
|
||||||
|
profile: profile,
|
||||||
|
zone: &zone,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil, provider.NewSoftError(fmt.Errorf("failed to list hosted zones: %w", err))
|
|
||||||
}
|
}
|
||||||
if tagErr != nil {
|
if tagErr != nil {
|
||||||
return nil, provider.NewSoftError(fmt.Errorf("failed to list zones tags: %w", tagErr))
|
return nil, provider.NewSoftError(fmt.Errorf("failed to list zones tags: %w", tagErr))
|
||||||
@ -386,7 +381,7 @@ func (p *AWSProvider) zones(ctx context.Context) (map[string]*profiledZone, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, zone := range zones {
|
for _, zone := range zones {
|
||||||
log.Debugf("Considering zone: %s (domain: %s)", aws.StringValue(zone.zone.Id), aws.StringValue(zone.zone.Name))
|
log.Debugf("Considering zone: %s (domain: %s)", *zone.zone.Id, *zone.zone.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.zonesCache.duration > time.Duration(0) {
|
if p.zonesCache.duration > time.Duration(0) {
|
||||||
@ -415,92 +410,93 @@ func (p *AWSProvider) Records(ctx context.Context) (endpoints []*endpoint.Endpoi
|
|||||||
|
|
||||||
func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZone) ([]*endpoint.Endpoint, error) {
|
func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZone) ([]*endpoint.Endpoint, error) {
|
||||||
endpoints := make([]*endpoint.Endpoint, 0)
|
endpoints := make([]*endpoint.Endpoint, 0)
|
||||||
f := func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool) {
|
|
||||||
for _, r := range resp.ResourceRecordSets {
|
|
||||||
newEndpoints := make([]*endpoint.Endpoint, 0)
|
|
||||||
|
|
||||||
if !p.SupportedRecordType(aws.StringValue(r.Type)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var ttl endpoint.TTL
|
|
||||||
if r.TTL != nil {
|
|
||||||
ttl = endpoint.TTL(*r.TTL)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(r.ResourceRecords) > 0 {
|
|
||||||
targets := make([]string, len(r.ResourceRecords))
|
|
||||||
for idx, rr := range r.ResourceRecords {
|
|
||||||
targets[idx] = aws.StringValue(rr.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
ep := endpoint.NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), aws.StringValue(r.Type), ttl, targets...)
|
|
||||||
if aws.StringValue(r.Type) == endpoint.RecordTypeCNAME {
|
|
||||||
ep = ep.WithProviderSpecific(providerSpecificAlias, "false")
|
|
||||||
}
|
|
||||||
newEndpoints = append(newEndpoints, ep)
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.AliasTarget != nil {
|
|
||||||
// Alias records don't have TTLs so provide the default to match the TXT generation
|
|
||||||
if ttl == 0 {
|
|
||||||
ttl = recordTTL
|
|
||||||
}
|
|
||||||
ep := endpoint.
|
|
||||||
NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeA, ttl, aws.StringValue(r.AliasTarget.DNSName)).
|
|
||||||
WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", aws.BoolValue(r.AliasTarget.EvaluateTargetHealth))).
|
|
||||||
WithProviderSpecific(providerSpecificAlias, "true")
|
|
||||||
newEndpoints = append(newEndpoints, ep)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ep := range newEndpoints {
|
|
||||||
if r.SetIdentifier != nil {
|
|
||||||
ep.SetIdentifier = aws.StringValue(r.SetIdentifier)
|
|
||||||
switch {
|
|
||||||
case r.Weight != nil:
|
|
||||||
ep.WithProviderSpecific(providerSpecificWeight, fmt.Sprintf("%d", aws.Int64Value(r.Weight)))
|
|
||||||
case r.Region != nil:
|
|
||||||
ep.WithProviderSpecific(providerSpecificRegion, aws.StringValue(r.Region))
|
|
||||||
case r.Failover != nil:
|
|
||||||
ep.WithProviderSpecific(providerSpecificFailover, aws.StringValue(r.Failover))
|
|
||||||
case r.MultiValueAnswer != nil && aws.BoolValue(r.MultiValueAnswer):
|
|
||||||
ep.WithProviderSpecific(providerSpecificMultiValueAnswer, "")
|
|
||||||
case r.GeoLocation != nil:
|
|
||||||
if r.GeoLocation.ContinentCode != nil {
|
|
||||||
ep.WithProviderSpecific(providerSpecificGeolocationContinentCode, aws.StringValue(r.GeoLocation.ContinentCode))
|
|
||||||
} else {
|
|
||||||
if r.GeoLocation.CountryCode != nil {
|
|
||||||
ep.WithProviderSpecific(providerSpecificGeolocationCountryCode, aws.StringValue(r.GeoLocation.CountryCode))
|
|
||||||
}
|
|
||||||
if r.GeoLocation.SubdivisionCode != nil {
|
|
||||||
ep.WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, aws.StringValue(r.GeoLocation.SubdivisionCode))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// one of the above needs to be set, otherwise SetIdentifier doesn't make sense
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.HealthCheckId != nil {
|
|
||||||
ep.WithProviderSpecific(providerSpecificHealthCheckID, aws.StringValue(r.HealthCheckId))
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints = append(endpoints, ep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, z := range zones {
|
for _, z := range zones {
|
||||||
params := &route53.ListResourceRecordSetsInput{
|
|
||||||
HostedZoneId: z.zone.Id,
|
|
||||||
MaxItems: aws.String(route53PageSize),
|
|
||||||
}
|
|
||||||
|
|
||||||
client := p.clients[z.profile]
|
client := p.clients[z.profile]
|
||||||
if err := client.ListResourceRecordSetsPagesWithContext(ctx, params, f); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list resource records sets for zone %s using aws profile %q: %w", *z.zone.Id, z.profile, err)
|
paginator := route53.NewListResourceRecordSetsPaginator(client, &route53.ListResourceRecordSetsInput{
|
||||||
|
HostedZoneId: z.zone.Id,
|
||||||
|
MaxItems: aws.Int32(route53PageSize),
|
||||||
|
})
|
||||||
|
|
||||||
|
for paginator.HasMorePages() {
|
||||||
|
resp, err := paginator.NextPage(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to list resource records sets for zone %s using aws profile %q: %w", *z.zone.Id, z.profile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range resp.ResourceRecordSets {
|
||||||
|
newEndpoints := make([]*endpoint.Endpoint, 0)
|
||||||
|
|
||||||
|
if !p.SupportedRecordType(r.Type) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var ttl endpoint.TTL
|
||||||
|
if r.TTL != nil {
|
||||||
|
ttl = endpoint.TTL(*r.TTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.ResourceRecords) > 0 {
|
||||||
|
targets := make([]string, len(r.ResourceRecords))
|
||||||
|
for idx, rr := range r.ResourceRecords {
|
||||||
|
targets[idx] = *rr.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := endpoint.NewEndpointWithTTL(wildcardUnescape(*r.Name), string(r.Type), ttl, targets...)
|
||||||
|
if r.Type == endpoint.RecordTypeCNAME {
|
||||||
|
ep = ep.WithProviderSpecific(providerSpecificAlias, "false")
|
||||||
|
}
|
||||||
|
newEndpoints = append(newEndpoints, ep)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.AliasTarget != nil {
|
||||||
|
// Alias records don't have TTLs so provide the default to match the TXT generation
|
||||||
|
if ttl == 0 {
|
||||||
|
ttl = recordTTL
|
||||||
|
}
|
||||||
|
ep := endpoint.
|
||||||
|
NewEndpointWithTTL(wildcardUnescape(*r.Name), endpoint.RecordTypeA, ttl, *r.AliasTarget.DNSName).
|
||||||
|
WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", r.AliasTarget.EvaluateTargetHealth)).
|
||||||
|
WithProviderSpecific(providerSpecificAlias, "true")
|
||||||
|
newEndpoints = append(newEndpoints, ep)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ep := range newEndpoints {
|
||||||
|
if r.SetIdentifier != nil {
|
||||||
|
ep.SetIdentifier = *r.SetIdentifier
|
||||||
|
switch {
|
||||||
|
case r.Weight != nil:
|
||||||
|
ep.WithProviderSpecific(providerSpecificWeight, fmt.Sprintf("%d", *r.Weight))
|
||||||
|
case r.Region != "":
|
||||||
|
ep.WithProviderSpecific(providerSpecificRegion, string(r.Region))
|
||||||
|
case r.Failover != "":
|
||||||
|
ep.WithProviderSpecific(providerSpecificFailover, string(r.Failover))
|
||||||
|
case r.MultiValueAnswer != nil && *r.MultiValueAnswer:
|
||||||
|
ep.WithProviderSpecific(providerSpecificMultiValueAnswer, "")
|
||||||
|
case r.GeoLocation != nil:
|
||||||
|
if r.GeoLocation.ContinentCode != nil {
|
||||||
|
ep.WithProviderSpecific(providerSpecificGeolocationContinentCode, *r.GeoLocation.ContinentCode)
|
||||||
|
} else {
|
||||||
|
if r.GeoLocation.CountryCode != nil {
|
||||||
|
ep.WithProviderSpecific(providerSpecificGeolocationCountryCode, *r.GeoLocation.CountryCode)
|
||||||
|
}
|
||||||
|
if r.GeoLocation.SubdivisionCode != nil {
|
||||||
|
ep.WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, *r.GeoLocation.SubdivisionCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// one of the above needs to be set, otherwise SetIdentifier doesn't make sense
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HealthCheckId != nil {
|
||||||
|
ep.WithProviderSpecific(providerSpecificHealthCheckID, *r.HealthCheckId)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints = append(endpoints, ep)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,9 +556,9 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint
|
|||||||
}
|
}
|
||||||
|
|
||||||
combined := make(Route53Changes, 0, len(deletes)+len(creates)+len(updates))
|
combined := make(Route53Changes, 0, len(deletes)+len(creates)+len(updates))
|
||||||
combined = append(combined, p.newChanges(route53.ChangeActionCreate, creates)...)
|
combined = append(combined, p.newChanges(route53types.ChangeActionCreate, creates)...)
|
||||||
combined = append(combined, p.newChanges(route53.ChangeActionUpsert, updates)...)
|
combined = append(combined, p.newChanges(route53types.ChangeActionUpsert, updates)...)
|
||||||
combined = append(combined, p.newChanges(route53.ChangeActionDelete, deletes)...)
|
combined = append(combined, p.newChanges(route53types.ChangeActionDelete, deletes)...)
|
||||||
return combined
|
return combined
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +571,7 @@ func (p *AWSProvider) GetDomainFilter() endpoint.DomainFilterInterface {
|
|||||||
}
|
}
|
||||||
zoneNames := []string(nil)
|
zoneNames := []string(nil)
|
||||||
for _, z := range zones {
|
for _, z := range zones {
|
||||||
zoneNames = append(zoneNames, aws.StringValue(z.Name), "."+aws.StringValue(z.Name))
|
zoneNames = append(zoneNames, *z.Name, "."+*z.Name)
|
||||||
}
|
}
|
||||||
log.Infof("Applying provider record filter for domains: %v", zoneNames)
|
log.Infof("Applying provider record filter for domains: %v", zoneNames)
|
||||||
return endpoint.NewDomainFilter(zoneNames)
|
return endpoint.NewDomainFilter(zoneNames)
|
||||||
@ -591,8 +587,8 @@ func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e
|
|||||||
updateChanges := p.createUpdateChanges(changes.UpdateNew, changes.UpdateOld)
|
updateChanges := p.createUpdateChanges(changes.UpdateNew, changes.UpdateOld)
|
||||||
|
|
||||||
combinedChanges := make(Route53Changes, 0, len(changes.Delete)+len(changes.Create)+len(updateChanges))
|
combinedChanges := make(Route53Changes, 0, len(changes.Delete)+len(changes.Create)+len(updateChanges))
|
||||||
combinedChanges = append(combinedChanges, p.newChanges(route53.ChangeActionCreate, changes.Create)...)
|
combinedChanges = append(combinedChanges, p.newChanges(route53types.ChangeActionCreate, changes.Create)...)
|
||||||
combinedChanges = append(combinedChanges, p.newChanges(route53.ChangeActionDelete, changes.Delete)...)
|
combinedChanges = append(combinedChanges, p.newChanges(route53types.ChangeActionDelete, changes.Delete)...)
|
||||||
combinedChanges = append(combinedChanges, updateChanges...)
|
combinedChanges = append(combinedChanges, updateChanges...)
|
||||||
|
|
||||||
return p.submitChanges(ctx, combinedChanges, zones)
|
return p.submitChanges(ctx, combinedChanges, zones)
|
||||||
@ -615,7 +611,7 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
|
|||||||
var failedZones []string
|
var failedZones []string
|
||||||
for z, cs := range changesByZone {
|
for z, cs := range changesByZone {
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"zoneName": aws.StringValue(zones[z].zone.Name),
|
"zoneName": *zones[z].zone.Name,
|
||||||
"zoneID": z,
|
"zoneID": z,
|
||||||
"profile": zones[z].profile,
|
"profile": zones[z].profile,
|
||||||
})
|
})
|
||||||
@ -634,13 +630,13 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range b {
|
for _, c := range b {
|
||||||
log.Infof("Desired change: %s %s %s", *c.Action, *c.ResourceRecordSet.Name, *c.ResourceRecordSet.Type)
|
log.Infof("Desired change: %s %s %s", c.Action, *c.ResourceRecordSet.Name, c.ResourceRecordSet.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.dryRun {
|
if !p.dryRun {
|
||||||
params := &route53.ChangeResourceRecordSetsInput{
|
params := &route53.ChangeResourceRecordSetsInput{
|
||||||
HostedZoneId: aws.String(z),
|
HostedZoneId: aws.String(z),
|
||||||
ChangeBatch: &route53.ChangeBatch{
|
ChangeBatch: &route53types.ChangeBatch{
|
||||||
Changes: b.Route53Changes(),
|
Changes: b.Route53Changes(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -648,8 +644,8 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
|
|||||||
successfulChanges := 0
|
successfulChanges := 0
|
||||||
|
|
||||||
client := p.clients[zones[z].profile]
|
client := p.clients[zones[z].profile]
|
||||||
if _, err := client.ChangeResourceRecordSetsWithContext(ctx, params); err != nil {
|
if _, err := client.ChangeResourceRecordSets(ctx, params); err != nil {
|
||||||
log.Errorf("Failure in zone %s when submitting change batch: %v", aws.StringValue(zones[z].zone.Name), err)
|
log.Errorf("Failure in zone %s when submitting change batch: %v", *zones[z].zone.Name, err)
|
||||||
|
|
||||||
changesByOwnership := groupChangesByNameAndOwnershipRelation(b)
|
changesByOwnership := groupChangesByNameAndOwnershipRelation(b)
|
||||||
|
|
||||||
@ -658,12 +654,12 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
|
|||||||
|
|
||||||
for _, changes := range changesByOwnership {
|
for _, changes := range changesByOwnership {
|
||||||
for _, c := range changes {
|
for _, c := range changes {
|
||||||
log.Debugf("Desired change: %s %s %s", *c.Action, *c.ResourceRecordSet.Name, *c.ResourceRecordSet.Type)
|
log.Debugf("Desired change: %s %s %s", c.Action, *c.ResourceRecordSet.Name, c.ResourceRecordSet.Type)
|
||||||
}
|
}
|
||||||
params.ChangeBatch = &route53.ChangeBatch{
|
params.ChangeBatch = &route53types.ChangeBatch{
|
||||||
Changes: changes.Route53Changes(),
|
Changes: changes.Route53Changes(),
|
||||||
}
|
}
|
||||||
if _, err := client.ChangeResourceRecordSetsWithContext(ctx, params); err != nil {
|
if _, err := client.ChangeResourceRecordSets(ctx, params); err != nil {
|
||||||
failedUpdate = true
|
failedUpdate = true
|
||||||
log.Errorf("Failed submitting change (error: %v), it will be retried in a separate change batch in the next iteration", err)
|
log.Errorf("Failed submitting change (error: %v), it will be retried in a separate change batch in the next iteration", err)
|
||||||
p.failedChangesQueue[z] = append(p.failedChangesQueue[z], changes...)
|
p.failedChangesQueue[z] = append(p.failedChangesQueue[z], changes...)
|
||||||
@ -702,7 +698,7 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newChanges returns a collection of Changes based on the given records and action.
|
// newChanges returns a collection of Changes based on the given records and action.
|
||||||
func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) Route53Changes {
|
func (p *AWSProvider) newChanges(action route53types.ChangeAction, endpoints []*endpoint.Endpoint) Route53Changes {
|
||||||
changes := make(Route53Changes, 0, len(endpoints))
|
changes := make(Route53Changes, 0, len(endpoints))
|
||||||
|
|
||||||
for _, endpoint := range endpoints {
|
for _, endpoint := range endpoints {
|
||||||
@ -711,8 +707,10 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint)
|
|||||||
if dualstack {
|
if dualstack {
|
||||||
// make a copy of change, modify RRS type to AAAA, then add new change
|
// make a copy of change, modify RRS type to AAAA, then add new change
|
||||||
rrs := *change.ResourceRecordSet
|
rrs := *change.ResourceRecordSet
|
||||||
change2 := &Route53Change{Change: route53.Change{Action: change.Action, ResourceRecordSet: &rrs}}
|
change2 := &Route53Change{
|
||||||
change2.ResourceRecordSet.Type = aws.String(route53.RRTypeAaaa)
|
Change: route53types.Change{Action: change.Action, ResourceRecordSet: &rrs},
|
||||||
|
}
|
||||||
|
change2.ResourceRecordSet.Type = route53types.RRTypeAaaa
|
||||||
changes = append(changes, change2)
|
changes = append(changes, change2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -774,11 +772,11 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoi
|
|||||||
// returned Change is based on the given record by the given action, e.g.
|
// 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=ChangeActionCreate returns a change for creation of the record and
|
||||||
// action=ChangeActionDelete returns a change for deletion of the record.
|
// 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 route53types.ChangeAction, ep *endpoint.Endpoint) (*Route53Change, bool) {
|
||||||
change := &Route53Change{
|
change := &Route53Change{
|
||||||
Change: route53.Change{
|
Change: route53types.Change{
|
||||||
Action: aws.String(action),
|
Action: action,
|
||||||
ResourceRecordSet: &route53.ResourceRecordSet{
|
ResourceRecordSet: &route53types.ResourceRecordSet{
|
||||||
Name: aws.String(ep.DNSName),
|
Name: aws.String(ep.DNSName),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -793,24 +791,24 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C
|
|||||||
if val, ok := ep.Labels[endpoint.DualstackLabelKey]; ok {
|
if val, ok := ep.Labels[endpoint.DualstackLabelKey]; ok {
|
||||||
dualstack = val == "true"
|
dualstack = val == "true"
|
||||||
}
|
}
|
||||||
change.ResourceRecordSet.Type = aws.String(route53.RRTypeA)
|
change.ResourceRecordSet.Type = route53types.RRTypeA
|
||||||
change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{
|
change.ResourceRecordSet.AliasTarget = &route53types.AliasTarget{
|
||||||
DNSName: aws.String(ep.Targets[0]),
|
DNSName: aws.String(ep.Targets[0]),
|
||||||
HostedZoneId: aws.String(cleanZoneID(targetHostedZone)),
|
HostedZoneId: aws.String(cleanZoneID(targetHostedZone)),
|
||||||
EvaluateTargetHealth: aws.Bool(evalTargetHealth),
|
EvaluateTargetHealth: evalTargetHealth,
|
||||||
}
|
}
|
||||||
change.sizeBytes += len([]byte(ep.Targets[0]))
|
change.sizeBytes += len([]byte(ep.Targets[0]))
|
||||||
change.sizeValues += 1
|
change.sizeValues += 1
|
||||||
} else {
|
} else {
|
||||||
change.ResourceRecordSet.Type = aws.String(ep.RecordType)
|
change.ResourceRecordSet.Type = route53types.RRType(ep.RecordType)
|
||||||
if !ep.RecordTTL.IsConfigured() {
|
if !ep.RecordTTL.IsConfigured() {
|
||||||
change.ResourceRecordSet.TTL = aws.Int64(recordTTL)
|
change.ResourceRecordSet.TTL = aws.Int64(recordTTL)
|
||||||
} else {
|
} else {
|
||||||
change.ResourceRecordSet.TTL = aws.Int64(int64(ep.RecordTTL))
|
change.ResourceRecordSet.TTL = aws.Int64(int64(ep.RecordTTL))
|
||||||
}
|
}
|
||||||
change.ResourceRecordSet.ResourceRecords = make([]*route53.ResourceRecord, len(ep.Targets))
|
change.ResourceRecordSet.ResourceRecords = make([]route53types.ResourceRecord, len(ep.Targets))
|
||||||
for idx, val := range ep.Targets {
|
for idx, val := range ep.Targets {
|
||||||
change.ResourceRecordSet.ResourceRecords[idx] = &route53.ResourceRecord{
|
change.ResourceRecordSet.ResourceRecords[idx] = route53types.ResourceRecord{
|
||||||
Value: aws.String(val),
|
Value: aws.String(val),
|
||||||
}
|
}
|
||||||
change.sizeBytes += len([]byte(val))
|
change.sizeBytes += len([]byte(val))
|
||||||
@ -818,7 +816,7 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if action == route53.ChangeActionUpsert {
|
if action == route53types.ChangeActionUpsert {
|
||||||
// If the value of the Action element is UPSERT, each ResourceRecord element and each character in a Value
|
// If the value of the Action element is UPSERT, each ResourceRecord element and each character in a Value
|
||||||
// element is counted twice
|
// element is counted twice
|
||||||
change.sizeBytes *= 2
|
change.sizeBytes *= 2
|
||||||
@ -837,16 +835,16 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C
|
|||||||
change.ResourceRecordSet.Weight = aws.Int64(weight)
|
change.ResourceRecordSet.Weight = aws.Int64(weight)
|
||||||
}
|
}
|
||||||
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificRegion); ok {
|
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificRegion); ok {
|
||||||
change.ResourceRecordSet.Region = aws.String(prop)
|
change.ResourceRecordSet.Region = route53types.ResourceRecordSetRegion(prop)
|
||||||
}
|
}
|
||||||
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificFailover); ok {
|
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificFailover); ok {
|
||||||
change.ResourceRecordSet.Failover = aws.String(prop)
|
change.ResourceRecordSet.Failover = route53types.ResourceRecordSetFailover(prop)
|
||||||
}
|
}
|
||||||
if _, ok := ep.GetProviderSpecificProperty(providerSpecificMultiValueAnswer); ok {
|
if _, ok := ep.GetProviderSpecificProperty(providerSpecificMultiValueAnswer); ok {
|
||||||
change.ResourceRecordSet.MultiValueAnswer = aws.Bool(true)
|
change.ResourceRecordSet.MultiValueAnswer = aws.Bool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
geolocation := &route53.GeoLocation{}
|
geolocation := &route53types.GeoLocation{}
|
||||||
useGeolocation := false
|
useGeolocation := false
|
||||||
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificGeolocationContinentCode); ok {
|
if prop, ok := ep.GetProviderSpecificProperty(providerSpecificGeolocationContinentCode); ok {
|
||||||
geolocation.ContinentCode = aws.String(prop)
|
geolocation.ContinentCode = aws.String(prop)
|
||||||
@ -908,7 +906,7 @@ func groupChangesByNameAndOwnershipRelation(cs Route53Changes) map[string]Route5
|
|||||||
for _, v := range cs {
|
for _, v := range cs {
|
||||||
key := v.OwnedRecord
|
key := v.OwnedRecord
|
||||||
if key == "" {
|
if key == "" {
|
||||||
key = aws.StringValue(v.ResourceRecordSet.Name)
|
key = *v.ResourceRecordSet.Name
|
||||||
}
|
}
|
||||||
changesByOwnership[key] = append(changesByOwnership[key], v)
|
changesByOwnership[key] = append(changesByOwnership[key], v)
|
||||||
}
|
}
|
||||||
@ -918,8 +916,8 @@ func groupChangesByNameAndOwnershipRelation(cs Route53Changes) map[string]Route5
|
|||||||
func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string, profile string) (map[string]string, error) {
|
func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string, profile string) (map[string]string, error) {
|
||||||
client := p.clients[profile]
|
client := p.clients[profile]
|
||||||
|
|
||||||
response, err := client.ListTagsForResourceWithContext(ctx, &route53.ListTagsForResourceInput{
|
response, err := client.ListTagsForResource(ctx, &route53.ListTagsForResourceInput{
|
||||||
ResourceType: aws.String("hostedzone"),
|
ResourceType: route53types.TagResourceTypeHostedzone,
|
||||||
ResourceId: aws.String(zoneID),
|
ResourceId: aws.String(zoneID),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1006,10 +1004,10 @@ func batchChangeSet(cs Route53Changes, batchSize int, batchSizeBytes int, batchS
|
|||||||
|
|
||||||
func sortChangesByActionNameType(cs Route53Changes) Route53Changes {
|
func sortChangesByActionNameType(cs Route53Changes) Route53Changes {
|
||||||
sort.SliceStable(cs, func(i, j int) bool {
|
sort.SliceStable(cs, func(i, j int) bool {
|
||||||
if *cs[i].Action > *cs[j].Action {
|
if cs[i].Action > cs[j].Action {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if *cs[i].Action < *cs[j].Action {
|
if cs[i].Action < cs[j].Action {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if *cs[i].ResourceRecordSet.Name < *cs[j].ResourceRecordSet.Name {
|
if *cs[i].ResourceRecordSet.Name < *cs[j].ResourceRecordSet.Name {
|
||||||
@ -1018,7 +1016,7 @@ func sortChangesByActionNameType(cs Route53Changes) Route53Changes {
|
|||||||
if *cs[i].ResourceRecordSet.Name > *cs[j].ResourceRecordSet.Name {
|
if *cs[i].ResourceRecordSet.Name > *cs[j].ResourceRecordSet.Name {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return *cs[i].ResourceRecordSet.Type < *cs[j].ResourceRecordSet.Type
|
return cs[i].ResourceRecordSet.Type < cs[j].ResourceRecordSet.Type
|
||||||
})
|
})
|
||||||
|
|
||||||
return cs
|
return cs
|
||||||
@ -1029,34 +1027,34 @@ func changesByZone(zones map[string]*profiledZone, changeSet Route53Changes) map
|
|||||||
changes := make(map[string]Route53Changes)
|
changes := make(map[string]Route53Changes)
|
||||||
|
|
||||||
for _, z := range zones {
|
for _, z := range zones {
|
||||||
changes[aws.StringValue(z.zone.Id)] = Route53Changes{}
|
changes[*z.zone.Id] = Route53Changes{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range changeSet {
|
for _, c := range changeSet {
|
||||||
hostname := provider.EnsureTrailingDot(aws.StringValue(c.ResourceRecordSet.Name))
|
hostname := provider.EnsureTrailingDot(*c.ResourceRecordSet.Name)
|
||||||
|
|
||||||
zones := suitableZones(hostname, zones)
|
zones := suitableZones(hostname, zones)
|
||||||
if len(zones) == 0 {
|
if len(zones) == 0 {
|
||||||
log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", c.String())
|
log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", *c.ResourceRecordSet.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, z := range zones {
|
for _, z := range zones {
|
||||||
if c.ResourceRecordSet.AliasTarget != nil && aws.StringValue(c.ResourceRecordSet.AliasTarget.HostedZoneId) == sameZoneAlias {
|
if c.ResourceRecordSet.AliasTarget != nil && *c.ResourceRecordSet.AliasTarget.HostedZoneId == sameZoneAlias {
|
||||||
// alias record is to be created; target needs to be in the same zone as endpoint
|
// alias record is to be created; target needs to be in the same zone as endpoint
|
||||||
// if it's not, this will fail
|
// if it's not, this will fail
|
||||||
rrset := *c.ResourceRecordSet
|
rrset := *c.ResourceRecordSet
|
||||||
aliasTarget := *rrset.AliasTarget
|
aliasTarget := *rrset.AliasTarget
|
||||||
aliasTarget.HostedZoneId = aws.String(cleanZoneID(aws.StringValue(z.zone.Id)))
|
aliasTarget.HostedZoneId = aws.String(cleanZoneID(*z.zone.Id))
|
||||||
rrset.AliasTarget = &aliasTarget
|
rrset.AliasTarget = &aliasTarget
|
||||||
c = &Route53Change{
|
c = &Route53Change{
|
||||||
Change: route53.Change{
|
Change: route53types.Change{
|
||||||
Action: c.Action,
|
Action: c.Action,
|
||||||
ResourceRecordSet: &rrset,
|
ResourceRecordSet: &rrset,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changes[aws.StringValue(z.zone.Id)] = append(changes[aws.StringValue(z.zone.Id)], c)
|
changes[*z.zone.Id] = append(changes[*z.zone.Id], c)
|
||||||
log.Debugf("Adding %s to zone %s [Id: %s]", hostname, aws.StringValue(z.zone.Name), aws.StringValue(z.zone.Id))
|
log.Debugf("Adding %s to zone %s [Id: %s]", hostname, *z.zone.Name, *z.zone.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1078,10 +1076,10 @@ func suitableZones(hostname string, zones map[string]*profiledZone) []*profiledZ
|
|||||||
var publicZone *profiledZone
|
var publicZone *profiledZone
|
||||||
|
|
||||||
for _, z := range zones {
|
for _, z := range zones {
|
||||||
if aws.StringValue(z.zone.Name) == hostname || strings.HasSuffix(hostname, "."+aws.StringValue(z.zone.Name)) {
|
if *z.zone.Name == hostname || strings.HasSuffix(hostname, "."+*z.zone.Name) {
|
||||||
if z.zone.Config == nil || !aws.BoolValue(z.zone.Config.PrivateZone) {
|
if z.zone.Config == nil || !z.zone.Config.PrivateZone {
|
||||||
// Only select the best matching public zone
|
// Only select the best matching public zone
|
||||||
if publicZone == nil || len(aws.StringValue(z.zone.Name)) > len(aws.StringValue(publicZone.zone.Name)) {
|
if publicZone == nil || len(*z.zone.Name) > len(*publicZone.zone.Name) {
|
||||||
publicZone = z
|
publicZone = z
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1156,11 +1154,11 @@ func cleanZoneID(id string) string {
|
|||||||
return strings.TrimPrefix(id, "/hostedzone/")
|
return strings.TrimPrefix(id, "/hostedzone/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *AWSProvider) SupportedRecordType(recordType string) bool {
|
func (p *AWSProvider) SupportedRecordType(recordType route53types.RRType) bool {
|
||||||
switch recordType {
|
switch recordType {
|
||||||
case "MX":
|
case route53types.RRTypeMx:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return provider.SupportedRecordType(recordType)
|
return provider.SupportedRecordType(string(recordType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,30 @@ func CreateDefaultV2Config(cfg *externaldns.Config) awsv2.Config {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateV2Configs(cfg *externaldns.Config) map[string]awsv2.Config {
|
||||||
|
result := make(map[string]awsv2.Config)
|
||||||
|
if len(cfg.AWSProfiles) == 0 || (len(cfg.AWSProfiles) == 1 && cfg.AWSProfiles[0] == "") {
|
||||||
|
cfg := CreateDefaultV2Config(cfg)
|
||||||
|
result[defaultAWSProfile] = cfg
|
||||||
|
} else {
|
||||||
|
for _, profile := range cfg.AWSProfiles {
|
||||||
|
cfg, err := newV2Config(
|
||||||
|
AWSSessionConfig{
|
||||||
|
AssumeRole: cfg.AWSAssumeRole,
|
||||||
|
AssumeRoleExternalID: cfg.AWSAssumeRoleExternalID,
|
||||||
|
APIRetries: cfg.AWSAPIRetries,
|
||||||
|
Profile: profile,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
result[profile] = cfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func CreateDefaultSession(cfg *externaldns.Config) *session.Session {
|
func CreateDefaultSession(cfg *externaldns.Config) *session.Session {
|
||||||
result, err := newSession(
|
result, err := newSession(
|
||||||
AWSSessionConfig{
|
AWSSessionConfig{
|
||||||
|
@ -17,8 +17,7 @@ limitations under the License.
|
|||||||
package provider
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -52,7 +51,7 @@ func (f ZoneTypeFilter) Match(rawZoneType interface{}) bool {
|
|||||||
case zoneTypePrivate:
|
case zoneTypePrivate:
|
||||||
return zoneType == zoneTypePrivate
|
return zoneType == zoneTypePrivate
|
||||||
}
|
}
|
||||||
case *route53.HostedZone:
|
case route53types.HostedZone:
|
||||||
// If the zone has no config we assume it's a public zone since the config's field
|
// If the zone has no config we assume it's a public zone since the config's field
|
||||||
// `PrivateZone` is false by default in go.
|
// `PrivateZone` is false by default in go.
|
||||||
if zoneType.Config == nil {
|
if zoneType.Config == nil {
|
||||||
@ -61,9 +60,9 @@ func (f ZoneTypeFilter) Match(rawZoneType interface{}) bool {
|
|||||||
|
|
||||||
switch f.zoneType {
|
switch f.zoneType {
|
||||||
case zoneTypePublic:
|
case zoneTypePublic:
|
||||||
return !aws.BoolValue(zoneType.Config.PrivateZone)
|
return !zoneType.Config.PrivateZone
|
||||||
case zoneTypePrivate:
|
case zoneTypePrivate:
|
||||||
return aws.BoolValue(zoneType.Config.PrivateZone)
|
return zoneType.Config.PrivateZone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@ package provider
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||||
"github.com/aws/aws-sdk-go/service/route53"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -28,8 +27,8 @@ import (
|
|||||||
func TestZoneTypeFilterMatch(t *testing.T) {
|
func TestZoneTypeFilterMatch(t *testing.T) {
|
||||||
publicZoneStr := "public"
|
publicZoneStr := "public"
|
||||||
privateZoneStr := "private"
|
privateZoneStr := "private"
|
||||||
publicZoneAWS := &route53.HostedZone{Config: &route53.HostedZoneConfig{PrivateZone: aws.Bool(false)}}
|
publicZoneAWS := route53types.HostedZone{Config: &route53types.HostedZoneConfig{PrivateZone: false}}
|
||||||
privateZoneAWS := &route53.HostedZone{Config: &route53.HostedZoneConfig{PrivateZone: aws.Bool(true)}}
|
privateZoneAWS := route53types.HostedZone{Config: &route53types.HostedZoneConfig{PrivateZone: true}}
|
||||||
|
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
zoneTypeFilter string
|
zoneTypeFilter string
|
||||||
@ -37,10 +36,10 @@ func TestZoneTypeFilterMatch(t *testing.T) {
|
|||||||
zones []interface{}
|
zones []interface{}
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"", true, []interface{}{publicZoneStr, privateZoneStr, &route53.HostedZone{}},
|
"", true, []interface{}{publicZoneStr, privateZoneStr, route53types.HostedZone{}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"public", true, []interface{}{publicZoneStr, publicZoneAWS, &route53.HostedZone{}},
|
"public", true, []interface{}{publicZoneStr, publicZoneAWS, route53types.HostedZone{}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"public", false, []interface{}{privateZoneStr, privateZoneAWS},
|
"public", false, []interface{}{privateZoneStr, privateZoneAWS},
|
||||||
@ -49,15 +48,17 @@ func TestZoneTypeFilterMatch(t *testing.T) {
|
|||||||
"private", true, []interface{}{privateZoneStr, privateZoneAWS},
|
"private", true, []interface{}{privateZoneStr, privateZoneAWS},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"private", false, []interface{}{publicZoneStr, publicZoneAWS, &route53.HostedZone{}},
|
"private", false, []interface{}{publicZoneStr, publicZoneAWS, route53types.HostedZone{}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unknown", false, []interface{}{publicZoneStr},
|
"unknown", false, []interface{}{publicZoneStr},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
zoneTypeFilter := NewZoneTypeFilter(tc.zoneTypeFilter)
|
t.Run(tc.zoneTypeFilter, func(t *testing.T) {
|
||||||
for _, zone := range tc.zones {
|
zoneTypeFilter := NewZoneTypeFilter(tc.zoneTypeFilter)
|
||||||
assert.Equal(t, tc.matches, zoneTypeFilter.Match(zone))
|
for _, zone := range tc.zones {
|
||||||
}
|
assert.Equal(t, tc.matches, zoneTypeFilter.Match(zone))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user