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

CLOUDFLARE: Use cloudflare-go (#1267)

* First pass at moving to cloudflare-go vs hand made implementation of cloudflare's API

* Final changes to use cloudflare-go

* Fix for proxy configuration failing

Forgot to set the ID when we created a new records.  This didn't fail in the integrations tests so I missed it.

* Add integration test

To prevent something like what I did from happening in the future.

* Fix bad messaging
This commit is contained in:
Brian Hartvigsen
2021-09-30 05:09:42 -06:00
committed by GitHub
parent 414f57274d
commit d8941a04bc
5 changed files with 121 additions and 390 deletions

View File

@ -6,8 +6,8 @@ import (
"log"
"net"
"strings"
"time"
"github.com/cloudflare/cloudflare-go"
"github.com/miekg/dns/dnsutil"
"github.com/StackExchange/dnscontrol/v3/models"
@ -73,6 +73,7 @@ type cloudflareProvider struct {
ipConversions []transform.IPConversion
ignoredLabels []string
manageRedirects bool
cfClient *cloudflare.API
}
func labelMatches(label string, matches []string) bool {
@ -172,8 +173,8 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
for i := len(records) - 1; i >= 0; i-- {
rec := records[i]
// Delete ignore labels
if labelMatches(dnsutil.TrimDomainName(rec.Original.(*cfRecord).Name, dc.Name), c.ignoredLabels) {
printer.Debugf("ignored_label: %s\n", rec.Original.(*cfRecord).Name)
if labelMatches(dnsutil.TrimDomainName(rec.Original.(cloudflare.DNSRecord).Name, dc.Name), c.ignoredLabels) {
printer.Debugf("ignored_label: %s\n", rec.Original.(cloudflare.DNSRecord).Name)
records = append(records[:i], records[i+1:]...)
}
}
@ -223,10 +224,10 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
if ex.Type == "PAGE_RULE" {
corrections = append(corrections, &models.Correction{
Msg: d.String(),
F: func() error { return c.deletePageRule(ex.Original.(*pageRule).ID, id) },
F: func() error { return c.deletePageRule(ex.Original.(cloudflare.PageRule).ID, id) },
})
} else {
corr := c.deleteRec(ex.Original.(*cfRecord), id)
corr := c.deleteRec(ex.Original.(cloudflare.DNSRecord), id)
// DS records must always have a corresponding NS record.
// Therefore, we remove DS records before any NS records.
if d.Existing.Type == "DS" {
@ -261,10 +262,10 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
if rec.Type == "PAGE_RULE" {
corrections = append(corrections, &models.Correction{
Msg: d.String(),
F: func() error { return c.updatePageRule(ex.Original.(*pageRule).ID, id, rec.GetTargetField()) },
F: func() error { return c.updatePageRule(ex.Original.(cloudflare.PageRule).ID, id, rec.GetTargetField()) },
})
} else {
e := ex.Original.(*cfRecord)
e := ex.Original.(cloudflare.DNSRecord)
proxy := e.Proxiable && rec.Metadata[metaProxy] != "off"
corrections = append(corrections, &models.Correction{
Msg: d.String(),
@ -458,6 +459,17 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
return nil, fmt.Errorf("if cloudflare apitoken is set, apikey and apiuser should not be provided")
}
var err error
if api.APIToken != "" {
api.cfClient, err = cloudflare.NewWithAPIToken(api.APIToken)
} else {
api.cfClient, err = cloudflare.New(api.APIKey, api.APIUser)
}
if err != nil {
return nil, fmt.Errorf("cloudflare credentials: %w", err)
}
// Check account data if set
api.AccountID, api.AccountName = m["accountid"], m["accountname"]
if (api.AccountID != "" && api.AccountName == "") || (api.AccountID == "" && api.AccountName != "") {
@ -558,33 +570,16 @@ func (c cfTarget) FQDN() string {
return strings.TrimRight(string(c), ".") + "."
}
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 *cfRecData `json:"data"`
Priority json.Number `json:"priority"`
}
func (c *cfRecord) nativeToRecord(domain string) (*models.RecordConfig, error) {
func (cfp *cloudflareProvider) nativeToRecord(domain string, c cloudflare.DNSRecord) (*models.RecordConfig, error) {
// normalize cname,mx,ns records with dots to be consistent with our config format.
if c.Type == "CNAME" || c.Type == "MX" || c.Type == "NS" || c.Type == "SRV" {
if c.Type == "CNAME" || c.Type == "MX" || c.Type == "NS" {
if c.Content != "." {
c.Content = c.Content + "."
}
}
rc := &models.RecordConfig{
TTL: c.TTL,
TTL: uint32(c.TTL),
Original: c,
}
rc.SetLabelFromFQDN(c.Name, domain)
@ -596,23 +591,17 @@ func (c *cfRecord) nativeToRecord(domain string) (*models.RecordConfig, error) {
switch rType := c.Type; rType { // #rtype_variations
case "MX":
var priority uint16
if c.Priority == "" {
priority = 0
} else {
p, err := c.Priority.Int64()
if err != nil {
return nil, fmt.Errorf("error decoding priority from cloudflare record: %w", err)
}
priority = uint16(p)
}
if err := rc.SetTargetMX(priority, c.Content); err != nil {
if err := rc.SetTargetMX(*c.Priority, c.Content); err != nil {
return nil, fmt.Errorf("unparsable MX record received from cloudflare: %w", err)
}
case "SRV":
data := *c.Data
if err := rc.SetTargetSRV(data.Priority, data.Weight, data.Port,
dnsutil.AddOrigin(data.Target.FQDN(), domain)); err != nil {
data := c.Data.(map[string]interface{})
target := data["target"].(string)
if target != "." {
target += "."
}
if err := rc.SetTargetSRV(uint16(data["priority"].(float64)), uint16(data["weight"].(float64)), uint16(data["port"].(float64)),
target); err != nil {
return nil, fmt.Errorf("unparsable SRV record received from cloudflare: %w", err)
}
default: // "A", "AAAA", "ANAME", "CAA", "CNAME", "NS", "PTR", "TXT"
@ -630,7 +619,7 @@ func getProxyMetadata(r *models.RecordConfig) map[string]string {
}
var proxied bool
if r.Original != nil {
proxied = r.Original.(*cfRecord).Proxied
proxied = *r.Original.(cloudflare.DNSRecord).Proxied
} else {
proxied = r.Metadata[metaProxy] != "off"
}