diff --git a/pkg/controller/provider/alicloud/handler.go b/pkg/controller/provider/alicloud/handler.go index 573129d11..50fb80a28 100644 --- a/pkg/controller/provider/alicloud/handler.go +++ b/pkg/controller/provider/alicloud/handler.go @@ -26,6 +26,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig access Access } @@ -36,7 +37,8 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met var err error this := &Handler{ - config: *config, + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, } accessKeyID := this.config.Properties["ACCESS_KEY_ID"] @@ -63,10 +65,6 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met return this, nil } -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (this *Handler) GetZones() (provider.DNSHostedZones, error) { raw := []alidns.Domain{} { diff --git a/pkg/controller/provider/aws/aliastarget.go b/pkg/controller/provider/aws/aliastarget.go index 3a58a109d..150cee102 100644 --- a/pkg/controller/provider/aws/aliastarget.go +++ b/pkg/controller/provider/aws/aliastarget.go @@ -75,43 +75,30 @@ func isAliasTarget(r *route53.ResourceRecordSet) bool { return aws.StringValue(r.Type) == route53.RRTypeA && r.AliasTarget != nil } -// buildRecordSetForAliasTarget transforms an A alias target to a CNAME dns.RecordSet -func buildRecordSetForAliasTarget(r *route53.ResourceRecordSet) *dns.RecordSet { - rs := dns.NewRecordSet(dns.RS_CNAME, 0, nil) +// buildRecordSetFromAliasTarget transforms an A alias target to a CNAME dns.RecordSet +func buildRecordSetFromAliasTarget(r *route53.ResourceRecordSet) *dns.RecordSet { + rs := dns.NewRecordSet(dns.RS_ALIAS, 0, nil) rs.IgnoreTTL = true // alias target has no settable TTL rs.Add(&dns.Record{Value: dns.NormalizeHostname(aws.StringValue(r.AliasTarget.DNSName))}) return rs } -// canConvertToAliasTarget determines if a given hostname belongs to an AWS load balancer. -// Returns nil otherwise. -func canConvertToAliasTarget(rset *dns.RecordSet) bool { - return getAliasTargetForAWSLoadBalancer(rset) != nil -} - -// getAliasTargetForAWSLoadBalancer determines if a given hostname belongs to an AWS load balancer -// and creates an AliasTarget. Returns nil otherwise. -func getAliasTargetForAWSLoadBalancer(rset *dns.RecordSet) *route53.AliasTarget { - if rset.Type == dns.RS_CNAME && len(rset.Records) == 1 { - target := dns.NormalizeHostname(rset.Records[0].Value) - hostedZone := canonicalHostedZone(target) - if hostedZone != "" { - return &route53.AliasTarget{ - DNSName: aws.String(target), - HostedZoneId: aws.String(hostedZone), - EvaluateTargetHealth: aws.Bool(true), - } - } +func buildResourceRecordSetForAliasTarget(name string, rset *dns.RecordSet) *route53.ResourceRecordSet { + target := dns.NormalizeHostname(rset.Records[0].Value) + hostedZone := canonicalHostedZone(target) + if hostedZone == "" { + return nil + } + aliasTarget := &route53.AliasTarget{ + DNSName: aws.String(target), + HostedZoneId: aws.String(hostedZone), + EvaluateTargetHealth: aws.Bool(true), } - return nil -} - -func buildResourceRecordSetForAliasTarget(name string, rset *dns.RecordSet) *route53.ResourceRecordSet { return &route53.ResourceRecordSet{ Name: aws.String(name), Type: aws.String(route53.RRTypeA), - AliasTarget: getAliasTargetForAWSLoadBalancer(rset), + AliasTarget: aliasTarget, } } diff --git a/pkg/controller/provider/aws/execution.go b/pkg/controller/provider/aws/execution.go index ad30b60db..5a58f2e18 100644 --- a/pkg/controller/provider/aws/execution.go +++ b/pkg/controller/provider/aws/execution.go @@ -68,8 +68,12 @@ func (this *Execution) addChange(action string, req *provider.ChangeRequest, dns this.Infof("%s %s record set %s[%s]: %s(%d)", action, rset.Type, name, this.zone.Id(), rset.RecordString(), rset.TTL) var rrs *route53.ResourceRecordSet - if canConvertToAliasTarget(rset) { + if rset.Type == dns.RS_ALIAS { rrs = buildResourceRecordSetForAliasTarget(name, rset) + if rrs == nil { + this.Errorf("Corrupted alias record set %s[%s]", name, this.zone.Id()) + return + } } else { rrs = buildResourceRecordSet(name, rset) } diff --git a/pkg/controller/provider/aws/handler.go b/pkg/controller/provider/aws/handler.go index a202a9757..13feab193 100644 --- a/pkg/controller/provider/aws/handler.go +++ b/pkg/controller/provider/aws/handler.go @@ -31,6 +31,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig awsConfig AWSConfig metrics provider.Metrics @@ -54,6 +55,8 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met } this := &Handler{ + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, awsConfig: awsConfig, metrics: metrics, @@ -89,10 +92,6 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met return this, nil } -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (this *Handler) GetZones() (provider.DNSHostedZones, error) { rt := provider.M_LISTZONES raw := []*route53.HostedZone{} @@ -144,18 +143,13 @@ 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) + rs = buildRecordSetFromAliasTarget(r) } else { rs = buildRecordSet(r) - if canConvertToAliasTarget(rs) { - migrations = append(migrations, r) - } } dnssets.AddRecordSetFromProvider(aws.StringValue(r.Name), rs) } @@ -164,10 +158,6 @@ func (this *Handler) GetZoneState(zone provider.DNSHostedZone) (provider.DNSZone return nil, err } - if len(migrations) > 0 { - this.migrateRecordsToAliasTargets(zone, migrations) - } - return provider.NewDNSZoneState(dnssets), nil } @@ -206,27 +196,12 @@ 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) +func (this *Handler) MapTarget(t provider.Target) provider.Target { + if t.GetRecordType() == dns.RS_CNAME { + hostedZone := canonicalHostedZone(t.GetHostName()) + if hostedZone != "" { + return provider.NewTarget(dns.RS_ALIAS, t.GetHostName(), t.GetEntry()) + } } + return t } diff --git a/pkg/controller/provider/azure/handler.go b/pkg/controller/provider/azure/handler.go index 5cf6f5ee6..5534ee4eb 100644 --- a/pkg/controller/provider/azure/handler.go +++ b/pkg/controller/provider/azure/handler.go @@ -33,6 +33,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig ctx context.Context metrics provider.Metrics @@ -45,8 +46,9 @@ var _ provider.DNSHandler = &Handler{} func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, metrics provider.Metrics) (provider.DNSHandler, error) { h := &Handler{ - config: *config, - metrics: metrics, + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, + metrics: metrics, } h.ctx = config.Context @@ -105,10 +107,6 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met var re = regexp.MustCompile("/resourceGroups/([^/]+)/") -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (h *Handler) GetZones() (provider.DNSHostedZones, error) { zones := provider.DNSHostedZones{} diff --git a/pkg/controller/provider/google/handler.go b/pkg/controller/provider/google/handler.go index b98d7b6d1..1ebf8246a 100644 --- a/pkg/controller/provider/google/handler.go +++ b/pkg/controller/provider/google/handler.go @@ -32,6 +32,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig credentials *google.Credentials client *http.Client @@ -46,8 +47,9 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met var err error this := &Handler{ - config: *config, - metrics: metrics, + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, + metrics: metrics, } scopes := []string{ // "https://www.googleapis.com/auth/compute", @@ -81,10 +83,6 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met return this, nil } -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (this *Handler) GetZones() (provider.DNSHostedZones, error) { rt := provider.M_LISTZONES raw := []*googledns.ManagedZone{} diff --git a/pkg/controller/provider/mock/handler.go b/pkg/controller/provider/mock/handler.go index e53ba92f3..61ebbe4fe 100644 --- a/pkg/controller/provider/mock/handler.go +++ b/pkg/controller/provider/mock/handler.go @@ -28,6 +28,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig ctx context.Context metrics provider.Metrics @@ -45,9 +46,10 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met mock := NewInMemory() h := &Handler{ - config: *config, - metrics: metrics, - mock: mock, + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, + metrics: metrics, + mock: mock, } mockConfig := MockConfig{} @@ -78,10 +80,6 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met return h, nil } -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (h *Handler) GetZones() (provider.DNSHostedZones, error) { zones := h.mock.GetZones() diff --git a/pkg/controller/provider/openstack/handler.go b/pkg/controller/provider/openstack/handler.go index fc81d3982..d4cc69163 100644 --- a/pkg/controller/provider/openstack/handler.go +++ b/pkg/controller/provider/openstack/handler.go @@ -28,6 +28,7 @@ import ( ) type Handler struct { + provider.DefaultDNSHandler config provider.DNSHandlerConfig ctx context.Context @@ -55,9 +56,10 @@ func NewHandler(logger logger.LogContext, config *provider.DNSHandlerConfig, met } h := Handler{ - config: *config, - ctx: config.Context, - client: designateClient{serviceClient: serviceClient, metrics: metrics}, + DefaultDNSHandler: provider.NewDefaultDNSHandler(TYPE_CODE), + config: *config, + ctx: config.Context, + client: designateClient{serviceClient: serviceClient, metrics: metrics}, } return &h, nil } @@ -107,10 +109,6 @@ func readAuthConfig(config *provider.DNSHandlerConfig) (*authConfig, error) { return &authConfig, nil } -func (h *Handler) ProviderType() string { - return TYPE_CODE -} - func (h *Handler) GetZones() (provider.DNSHostedZones, error) { hostedZones := provider.DNSHostedZones{} diff --git a/pkg/dns/provider/changemodel.go b/pkg/dns/provider/changemodel.go index acc1e75fd..cbd1789ac 100644 --- a/pkg/dns/provider/changemodel.go +++ b/pkg/dns/provider/changemodel.go @@ -258,7 +258,7 @@ func (this *ChangeModel) Exec(apply bool, delete bool, name string, done DoneHan oldset := view.dnssets[name] newset := dns.NewDNSSet(name) if !delete { - this.AddTargets(newset, oldset, targets...) + this.AddTargets(newset, oldset, p, targets...) } mod := false if oldset != nil { @@ -383,7 +383,7 @@ func (this *ChangeModel) setOwner(set *dns.DNSSet, targets []Target) bool { return false } -func (this *ChangeModel) AddTargets(set *dns.DNSSet, base *dns.DNSSet, targets ...Target) *dns.DNSSet { +func (this *ChangeModel) AddTargets(set *dns.DNSSet, base *dns.DNSSet, provider DNSProvider, targets ...Target) *dns.DNSSet { //if base != nil { // meta := base.Sets[RS_META] // if meta != nil { @@ -400,10 +400,9 @@ func (this *ChangeModel) AddTargets(set *dns.DNSSet, base *dns.DNSSet, targets . targetsets := set.Sets cnames := []string{} for _, t := range targets { - ty := t.GetRecordType() // use status calculated in entry ttl := t.GetEntry().TTL() - if ty == dns.RS_CNAME && len(targets) > 1 { + if t.GetRecordType() == dns.RS_CNAME && len(targets) > 1 { cnames = append(cnames, t.GetHostName()) addrs, err := net.LookupHost(t.GetHostName()) if err == nil { @@ -415,7 +414,8 @@ func (this *ChangeModel) AddTargets(set *dns.DNSSet, base *dns.DNSSet, targets . } this.Debugf("mapping target '%s' to A records: %s", t.GetHostName(), strings.Join(addrs, ",")) } else { - AddRecord(targetsets, ty, t.GetHostName(), ttl) + t = provider.MapTarget(t) + AddRecord(targetsets, t.GetRecordType(), t.GetHostName(), ttl) } } set.Sets = targetsets diff --git a/pkg/dns/provider/interface.go b/pkg/dns/provider/interface.go index 317c674ee..119c27b89 100644 --- a/pkg/dns/provider/interface.go +++ b/pkg/dns/provider/interface.go @@ -154,6 +154,23 @@ type DNSHandler interface { GetZones() (DNSHostedZones, error) GetZoneState(DNSHostedZone) (DNSZoneState, error) ExecuteRequests(logger logger.LogContext, zone DNSHostedZone, state DNSZoneState, reqs []*ChangeRequest) error + MapTarget(t Target) Target +} + +type DefaultDNSHandler struct { + providerType string +} + +func NewDefaultDNSHandler(providerType string) DefaultDNSHandler { + return DefaultDNSHandler{providerType} +} + +func (this *DefaultDNSHandler) ProviderType() string { + return this.providerType +} + +func (this *DefaultDNSHandler) MapTarget(t Target) Target { + return t } //////////////////////////////////////////////////////////////////////////////// @@ -179,6 +196,7 @@ type DNSProvider interface { Match(dns string) int AccountHash() string + MapTarget(t Target) Target } type DoneHandler interface { diff --git a/pkg/dns/provider/provider.go b/pkg/dns/provider/provider.go index b8f4d64a1..bd81420dc 100644 --- a/pkg/dns/provider/provider.go +++ b/pkg/dns/provider/provider.go @@ -117,6 +117,10 @@ func (this *DNSAccount) ExecuteRequests(logger logger.LogContext, zone DNSHosted return this.handler.ExecuteRequests(logger, zone, state, reqs) } +func (this *DNSAccount) MapTarget(t Target) Target { + return this.handler.MapTarget(t) +} + type AccountCache struct { lock sync.Mutex ttl time.Duration @@ -429,6 +433,10 @@ func (this *dnsProviderVersion) Match(dns string) int { return -1 } +func (this *dnsProviderVersion) MapTarget(t Target) Target { + return this.account.MapTarget(t) +} + func (this *dnsProviderVersion) setError(modified bool, err error) error { modified = this.object.SetSelection(utils.StringSet{}, utils.StringSet{}, &this.object.Status().Domains) || modified modified = this.object.SetSelection(utils.StringSet{}, utils.StringSet{}, &this.object.Status().Zones) || modified diff --git a/pkg/dns/records.go b/pkg/dns/records.go index e7c43f5f6..3a160cfce 100644 --- a/pkg/dns/records.go +++ b/pkg/dns/records.go @@ -22,6 +22,8 @@ import ( ) const RS_META = "META" +const RS_ALIAS = "ALIAS" // provider specific alias for CNAME record (e.g. AWS alias target) + const RS_TXT = "TXT" const RS_CNAME = "CNAME" const RS_A = "A"