From 638ee45e6cced34c5327f8baebf81e06ae04084a Mon Sep 17 00:00:00 2001 From: PJ Eby Date: Thu, 10 Aug 2017 16:02:06 -0400 Subject: [PATCH] Implement SRV support for CloudFlare provider (#174) * Implement SRV support for CloudFlare provider * go fmt * Use valid SRV names in SRV tests --- integrationTest/integration_test.go | 16 +++---- providers/cloudflare/cloudflareProvider.go | 52 +++++++++++++++------- providers/cloudflare/rest.go | 49 ++++++++++++++------ 3 files changed, 79 insertions(+), 38 deletions(-) mode change 100644 => 100755 integrationTest/integration_test.go diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go old mode 100644 new mode 100755 index 94ffaaff2..9623a391c --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -325,14 +325,14 @@ var tests = []*TestCase{ //SRV tc("Empty").IfHasCapability(providers.CanUseSRV), - tc("SRV record", srv("@", 5, 6, 7, "foo.com.")).IfHasCapability(providers.CanUseSRV), - tc("Second SRV record, same prio", srv("@", 5, 6, 7, "foo.com."), srv("@", 5, 60, 70, "foo2.com.")).IfHasCapability(providers.CanUseSRV), - tc("3 SRV", srv("@", 5, 6, 7, "foo.com."), srv("@", 5, 60, 70, "foo2.com."), srv("@", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV), - tc("Delete one", srv("@", 5, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV), - tc("Change Target", srv("@", 5, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), - tc("Change Priority", srv("@", 52, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), - tc("Change Weight", srv("@", 52, 62, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), - tc("Change Port", srv("@", 52, 62, 72, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), + tc("SRV record", srv("_service._protocol", 5, 6, 7, "foo.com.")).IfHasCapability(providers.CanUseSRV), + tc("Second SRV record, same prio", srv("_service._protocol", 5, 6, 7, "foo.com."), srv("_service._protocol", 5, 60, 70, "foo2.com.")).IfHasCapability(providers.CanUseSRV), + tc("3 SRV", srv("_service._protocol", 5, 6, 7, "foo.com."), srv("_service._protocol", 5, 60, 70, "foo2.com."), srv("_service._protocol", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV), + tc("Delete one", srv("_service._protocol", 5, 6, 7, "foo.com."), srv("_service._protocol", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV), + tc("Change Target", srv("_service._protocol", 5, 6, 7, "foo.com."), srv("_service._protocol", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), + tc("Change Priority", srv("_service._protocol", 52, 6, 7, "foo.com."), srv("_service._protocol", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), + tc("Change Weight", srv("_service._protocol", 52, 62, 7, "foo.com."), srv("_service._protocol", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), + tc("Change Port", srv("_service._protocol", 52, 62, 72, "foo.com."), srv("_service._protocol", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV), //CAA tc("Empty").IfHasCapability(providers.CanUseCAA), diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 8a3e4541b..6f23c6fac 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -34,7 +34,7 @@ Domain level metadata available: */ func init() { - providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseAlias) + providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseSRV, providers.CanUseAlias) providers.RegisterCustomRecordType("CF_REDIRECT", "CLOUDFLAREAPI", "") providers.RegisterCustomRecordType("CF_TEMP_REDIRECT", "CLOUDFLAREAPI", "") } @@ -321,29 +321,39 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS } // Used on the "existing" records. +type cfRecData struct { + Service string `json:"service"` + Proto string `json:"proto"` + Name string `json:"name"` + Priority uint16 `json:"priority"` + Weight uint16 `json:"weight"` + Port uint16 `json:"port"` + Target string `json:"target"` +} + type cfRecord struct { - ID string `json:"id"` - Type string `json:"type"` - Name string `json:"name"` - Content string `json:"content"` - Proxiable bool `json:"proxiable"` - Proxied bool `json:"proxied"` - TTL uint32 `json:"ttl"` - Locked bool `json:"locked"` - ZoneID string `json:"zone_id"` - ZoneName string `json:"zone_name"` - CreatedOn time.Time `json:"created_on"` - ModifiedOn time.Time `json:"modified_on"` - Data interface{} `json:"data"` - Priority uint16 `json:"priority"` + ID string `json:"id"` + Type string `json:"type"` + Name string `json:"name"` + Content string `json:"content"` + Proxiable bool `json:"proxiable"` + Proxied bool `json:"proxied"` + TTL uint32 `json:"ttl"` + Locked bool `json:"locked"` + ZoneID string `json:"zone_id"` + ZoneName string `json:"zone_name"` + CreatedOn time.Time `json:"created_on"` + ModifiedOn time.Time `json:"modified_on"` + Data *cfRecData `json:"data"` + Priority uint16 `json:"priority"` } func (c *cfRecord) toRecord(domain string) *models.RecordConfig { //normalize cname,mx,ns records with dots to be consistent with our config format. - if c.Type == "CNAME" || c.Type == "MX" || c.Type == "NS" { + if c.Type == "CNAME" || c.Type == "MX" || c.Type == "NS" || c.Type == "SRV" { c.Content = dnsutil.AddOrigin(c.Content+".", domain) } - return &models.RecordConfig{ + rc := &models.RecordConfig{ NameFQDN: c.Name, Type: c.Type, Target: c.Content, @@ -351,6 +361,14 @@ func (c *cfRecord) toRecord(domain string) *models.RecordConfig { TTL: c.TTL, Original: c, } + if c.Type == "SRV" { + data := *c.Data + rc.SrvPriority = data.Priority + rc.SrvWeight = data.Weight + rc.SrvPort = data.Port + rc.Target = dnsutil.AddOrigin(data.Target+".", domain) + } + return rc } func getProxyMetadata(r *models.RecordConfig) map[string]string { diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index 4b4db1570..1601ce902 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -116,13 +116,27 @@ func (c *CloudflareApi) createZone(domainName string) (string, error) { return id, err } +func cfSrvData(rec *models.RecordConfig) *cfRecData { + serverParts := strings.Split(rec.NameFQDN, ".") + return &cfRecData{ + Service: serverParts[0], + Proto: serverParts[1], + Name: strings.Join(serverParts[2:], "."), + Port: rec.SrvPort, + Priority: rec.SrvPriority, + Weight: rec.SrvWeight, + Target: rec.Target, + } +} + func (c *CloudflareApi) createRec(rec *models.RecordConfig, domainID string) []*models.Correction { type createRecord struct { - Name string `json:"name"` - Type string `json:"type"` - Content string `json:"content"` - TTL uint32 `json:"ttl"` - Priority uint16 `json:"priority"` + Name string `json:"name"` + Type string `json:"type"` + Content string `json:"content"` + TTL uint32 `json:"ttl"` + Priority uint16 `json:"priority"` + Data *cfRecData `json:"data"` } var id string content := rec.Target @@ -144,6 +158,10 @@ func (c *CloudflareApi) createRec(rec *models.RecordConfig, domainID string) []* Content: content, Priority: rec.MxPreference, } + if rec.Type == "SRV" { + cf.Data = cfSrvData(rec) + cf.Name = rec.NameFQDN + } endpoint := fmt.Sprintf(recordsURL, domainID) buf := &bytes.Buffer{} encoder := json.NewEncoder(buf) @@ -173,15 +191,20 @@ func (c *CloudflareApi) modifyRecord(domainID, recID string, proxied bool, rec * return fmt.Errorf("Cannot modify record if domain or record id are empty.") } type record struct { - ID string `json:"id"` - Proxied bool `json:"proxied"` - Name string `json:"name"` - Type string `json:"type"` - Content string `json:"content"` - Priority uint16 `json:"priority"` - TTL uint32 `json:"ttl"` + ID string `json:"id"` + Proxied bool `json:"proxied"` + Name string `json:"name"` + Type string `json:"type"` + Content string `json:"content"` + Priority uint16 `json:"priority"` + TTL uint32 `json:"ttl"` + Data *cfRecData `json:"data"` + } + r := record{recID, proxied, rec.Name, rec.Type, rec.Target, rec.MxPreference, rec.TTL, nil} + if rec.Type == "SRV" { + r.Data = cfSrvData(rec) + r.Name = rec.NameFQDN } - r := record{recID, proxied, rec.Name, rec.Type, rec.Target, rec.MxPreference, rec.TTL} endpoint := fmt.Sprintf(singleRecordURL, domainID, recID) buf := &bytes.Buffer{} encoder := json.NewEncoder(buf)