1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

#68 Registrar support for Route53 provider (#155)

* Added registrar support to Route53 provider
* ran gofmt on route53Provider
* Caveat: If you use r53 is a Registrar but not as a Dns Service Provider, DNSControl may be DNS-related API calls that you do not have IAM permissions to do.
This commit is contained in:
Norm MacLennan
2017-08-05 10:56:42 -04:00
committed by Tom Limoncelli
parent 8cff3128ea
commit 7f01a8c9ad
7 changed files with 5295 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ package route53
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"
@@ -12,20 +13,34 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/private/waiter"
r53 "github.com/aws/aws-sdk-go/service/route53"
r53d "github.com/aws/aws-sdk-go/service/route53domains"
"github.com/pkg/errors"
)
type route53Provider struct {
client *r53.Route53
zones map[string]*r53.HostedZone
client *r53.Route53
registrar *r53d.Route53Domains
zones map[string]*r53.HostedZone
}
func newRoute53(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
func newRoute53Reg(conf map[string]string) (providers.Registrar, error) {
return newRoute53(conf, nil)
}
func newRoute53Dsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
return newRoute53(conf, metadata)
}
func newRoute53(m map[string]string, metadata json.RawMessage) (*route53Provider, error) {
keyId, secretKey := m["KeyId"], m["SecretKey"]
// Route53 uses a global endpoint and route53domains
// currently only has a single regional endpoint in us-east-1
// http://docs.aws.amazon.com/general/latest/gr/rande.html#r53_region
config := &aws.Config{
Region: aws.String("us-west-2"),
Region: aws.String("us-east-1"),
}
if keyId != "" || secretKey != "" {
@@ -33,7 +48,7 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (providers.DNSSer
}
sess := session.New(config)
api := &route53Provider{client: r53.New(sess)}
api := &route53Provider{client: r53.New(sess), registrar: r53d.New(sess)}
err := api.getZones()
if err != nil {
return nil, err
@@ -42,8 +57,10 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (providers.DNSSer
}
func init() {
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53, providers.CanUsePTR, providers.CanUseSRV)
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53Dsp, providers.CanUsePTR, providers.CanUseSRV)
providers.RegisterRegistrarType("ROUTE53", newRoute53Reg)
}
func sPtr(s string) *string {
return &s
}
@@ -249,6 +266,69 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
}
func (r *route53Provider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
corrections := []*models.Correction{}
actualSet, err := r.getRegistrarNameservers(&dc.Name)
if err != nil {
return nil, err
}
sort.Strings(actualSet)
actual := strings.Join(actualSet, ",")
expectedSet := []string{}
for _, ns := range dc.Nameservers {
expectedSet = append(expectedSet, ns.Name)
}
sort.Strings(expectedSet)
expected := strings.Join(expectedSet, ",")
if actual != expected {
return []*models.Correction{
{
Msg: fmt.Sprintf("Update nameservers %s -> %s", actual, expected),
F: func() error {
operationId, err := r.updateRegistrarNameservers(dc.Name, expectedSet)
if err != nil {
return err
}
return r.waitUntilNameserversUpdate(operationId)
},
},
}, nil
}
return corrections, nil
}
func (r *route53Provider) getRegistrarNameservers(domainName *string) ([]string, error) {
domainDetail, err := r.registrar.GetDomainDetail(&r53d.GetDomainDetailInput{DomainName: domainName})
if err != nil {
return nil, err
}
nameservers := []string{}
for _, ns := range domainDetail.Nameservers {
nameservers = append(nameservers, *ns.Name)
}
return nameservers, nil
}
func (r *route53Provider) updateRegistrarNameservers(domainName string, nameservers []string) (*string, error) {
servers := []*r53d.Nameserver{}
for i := range nameservers {
servers = append(servers, &r53d.Nameserver{Name: &nameservers[i]})
}
domainUpdate, err := r.registrar.UpdateDomainNameservers(&r53d.UpdateDomainNameserversInput{DomainName: &domainName, Nameservers: servers})
if err != nil {
return nil, err
}
return domainUpdate.OperationId, nil
}
func (r *route53Provider) fetchRecordSets(zoneID *string) ([]*r53.ResourceRecordSet, error) {
if zoneID == nil || *zoneID == "" {
return nil, nil
@@ -301,3 +381,31 @@ func (r *route53Provider) EnsureDomainExists(domain string) error {
return err
}
func (r *route53Provider) waitUntilNameserversUpdate(operationId *string) error {
fmt.Print("Waiting for registrar update to complete...")
waiterCfg := waiter.Config{
Operation: "GetOperationDetail",
Delay: 30,
MaxAttempts: 10,
Acceptors: []waiter.WaitAcceptor{
{
State: "success",
Matcher: "path",
Argument: "Status",
Expected: "SUCCESSFUL",
},
},
}
w := waiter.Waiter{
Client: r.registrar,
Input: &r53d.GetOperationDetailInput{
OperationId: operationId,
},
Config: waiterCfg,
}
return w.Wait()
}