Skip to content

Commit

Permalink
aws-route53: migrate existing CNAME records to alias target if applic…
Browse files Browse the repository at this point in the history
…able

```improvement operator
aws-route53: migrate existing CNAME records to alias target if applicable
```
  • Loading branch information
MartinWeindel committed Jun 11, 2019
1 parent 3a238bc commit 6489869
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 14 deletions.
20 changes: 12 additions & 8 deletions pkg/controller/provider/aws/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ type Change struct {

type Execution struct {
logger.LogContext
handler *Handler
zone provider.DNSHostedZone
r53 *route53.Route53
zone provider.DNSHostedZone

changes map[string][]*Change
maxChangeCount int
changes map[string][]*Change
batchSize int
}

func NewExecution(logger logger.LogContext, h *Handler, zone provider.DNSHostedZone) *Execution {
return &Execution{LogContext: logger, handler: h, zone: zone, changes: map[string][]*Change{}, maxChangeCount: 50}
return &Execution{LogContext: logger, r53: h.r53, zone: zone, changes: map[string][]*Change{}, batchSize: h.awsConfig.BatchSize}
}

func buildResourceRecordSet(name string, rset *dns.RecordSet) *route53.ResourceRecordSet {
Expand Down Expand Up @@ -75,15 +75,19 @@ func (this *Execution) addChange(action string, req *provider.ChangeRequest, dns
}

change := &route53.Change{Action: aws.String(action), ResourceRecordSet: rrs}
this.changes[name] = append(this.changes[name], &Change{Change: change, Done: req.Done})
this.addRawChange(name, change, req.Done)
}

func (this *Execution) addRawChange(name string, change *route53.Change, done provider.DoneHandler) {
this.changes[name] = append(this.changes[name], &Change{Change: change, Done: done})
}

func (this *Execution) submitChanges(metrics provider.Metrics) error {
if len(this.changes) == 0 {
return nil
}

limitedChanges := limitChangeSet(this.changes, this.maxChangeCount)
limitedChanges := limitChangeSet(this.changes, this.batchSize)
this.Infof("require %d batches for %d dns names", len(limitedChanges), len(this.changes))
for i, changes := range limitedChanges {
this.Infof("processing batch %d for zone %s with %d requests", i+1, this.zone.Id(), len(changes))
Expand All @@ -103,7 +107,7 @@ func (this *Execution) submitChanges(metrics provider.Metrics) error {
}

metrics.AddRequests(provider.M_UPDATERECORDS, 1)
if _, err := this.handler.r53.ChangeResourceRecordSets(params); err != nil {
if _, err := this.r53.ChangeResourceRecordSets(params); err != nil {
this.Errorf("%d records in zone %s fail: %s", len(changes), this.zone.Id(), err)
for _, c := range changes {
if c.Done != nil {
Expand Down
62 changes: 56 additions & 6 deletions pkg/controller/provider/aws/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package aws

import (
"encoding/json"
"fmt"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/gardener/external-dns-management/pkg/dns/provider"
Expand All @@ -30,18 +31,32 @@ import (
)

type Handler struct {
config provider.DNSHandlerConfig
metrics provider.Metrics
sess *session.Session
r53 *route53.Route53
config provider.DNSHandlerConfig
awsConfig AWSConfig
metrics provider.Metrics
sess *session.Session
r53 *route53.Route53
}

type AWSConfig struct {
BatchSize int `json:"batchSize"`
}

var _ provider.DNSHandler = &Handler{}

func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, metrics provider.Metrics) (provider.DNSHandler, error) {
awsConfig := AWSConfig{BatchSize: 50}
if config.Config != nil {
err := json.Unmarshal(config.Config.Raw, &awsConfig)
if err != nil {
return nil, fmt.Errorf("unmarshal aws-route providerConfig failed with: %s", err)
}
}

this := &Handler{
config: *config,
metrics: metrics,
config: *config,
awsConfig: awsConfig,
metrics: metrics,
}
akid := this.config.Properties["AWS_ACCESS_KEY_ID"]
if akid == "" {
Expand Down Expand Up @@ -123,20 +138,30 @@ func buildRecordSet(r *route53.ResourceRecordSet) *dns.RecordSet {
func (this *Handler) GetZoneState(zone provider.DNSHostedZone) (provider.DNSZoneState, error) {
dnssets := dns.DNSSets{}

migrations := []*route53.ResourceRecordSet{}

aggr := func(r *route53.ResourceRecordSet) {
if dns.SupportedRecordType(aws.StringValue(r.Type)) {
var rs *dns.RecordSet
if isAliasTarget(r) {
rs = buildRecordSetForAliasTarget(r)
} else {
rs = buildRecordSet(r)
if canConvertToAliasTarget(rs) {
migrations = append(migrations, r)
}
}
dnssets.AddRecordSetFromProvider(aws.StringValue(r.Name), rs)
}
}
if err := this.handleRecordSets(zone.Id(), aggr); err != nil {
return nil, err
}

if len(migrations) > 0 {
this.migrateRecordsToAliasTargets(zone, migrations)
}

return provider.NewDNSZoneState(dnssets), nil
}

Expand Down Expand Up @@ -174,3 +199,28 @@ func (this *Handler) ExecuteRequests(logger logger.LogContext, zone provider.DNS
}
return exec.submitChanges(this.metrics)
}

func (this *Handler) migrateRecordsToAliasTargets(zone provider.DNSHostedZone, migrations []*route53.ResourceRecordSet) {
logContext := logger.NewContext("provider", "aws-route53").NewContext("zone", zone.Id())
logContext.Infof("migrating %d records to alias targets", len(migrations))
exec := NewExecution(logContext, this, zone)

for _, r := range migrations {
rs := buildRecordSet(r)
name := aws.StringValue(r.Name)
dnsset := dns.NewDNSSet(dns.NormalizeHostname(name))
dnsset.Sets[rs.Type] = rs

// delete old CNAME DNS record
change := &route53.Change{Action: aws.String(route53.ChangeActionDelete), ResourceRecordSet: r}
exec.addRawChange(name, change, nil)
// add A alias target record (implicitly converted dns.RecordSet)
r := &provider.ChangeRequest{Action: provider.R_CREATE, Type: aws.StringValue(r.Type), Addition: dnsset}
exec.addChange(route53.ChangeActionCreate, r, r.Addition)
}

err := exec.submitChanges(this.metrics)
if err != nil {
logContext.Warnf("Migrating to alias targets failed with %s", err)
}
}

0 comments on commit 6489869

Please sign in to comment.