diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html index c815e095e..1d359bbcb 100644 --- a/docs/_includes/matrix.html +++ b/docs/_includes/matrix.html @@ -922,8 +922,8 @@ - - + + diff --git a/docs/writing-providers.md b/docs/writing-providers.md index fddb7052a..8a357ea94 100644 --- a/docs/writing-providers.md +++ b/docs/writing-providers.md @@ -92,14 +92,14 @@ Pick a similar provider as your base. Providers basically fall into three general categories: * **zone:** The API requires you to upload the entire zone every time. (BIND). -* **incremental-record:** The API lets you add/change/delete individual DNS records. (ACTIVEDIR, CLOUDFLARE, NAMEDOTCOM, GCLOUD, ROUTE53) +* **incremental-record:** The API lets you add/change/delete individual DNS records. (ACTIVEDIR, CLOUDFLARE, DNSIMPLE, NAMEDOTCOM, GCLOUD, ROUTE53) * **incremental-label:** Like incremental-record, but if there are multiple records on a label (for example, example www.example.com has A and MX records), you have to replace all the records at that label. (GANDI_V5) * **incremental-label-type:** Like incremental-record, but updates to any records at a label have to be done by type. For example, if a label (www.example.com) has many A and MX records, even the smallest change to one of the A records requires replacing all the A records. Any changes to the MX records requires replacing all the MX records. If an A record is converted to a CNAME, one must remove all the A records in one call, and add the CNAME record with another call. This is deceptively difficult to get right; if you have the voice between incremental-label-type and incremental-label, pick incremental-label. -TODO: Categorize DNSIMPLE, NAMECHEAP +TODO: Categorize NAMECHEAP All providers use the "diff" module to detect differences. It takes two zones and returns records that are unchanged, created, deleted, diff --git a/go.mod b/go.mod index 1f3349d51..d8a149137 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/dgrijalva/jwt-go v3.2.1-0.20190620180102-5e25c22bd5d6+incompatible // indirect github.com/digitalocean/godo v1.30.0 - github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c + github.com/dnsimple/dnsimple-go v0.31.0 github.com/exoscale/egoscale v0.10.5 github.com/go-acme/lego v2.7.2+incompatible github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe diff --git a/go.sum b/go.sum index 81ebf5819..c6d7a6ef8 100644 --- a/go.sum +++ b/go.sum @@ -35,7 +35,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 h1:jbGlDKdzAZ92NzK65hUP98ri0/r50vVVvmZsFP/nIqo= github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI= -github.com/StackExchange/dnscontrol v0.2.8 h1:7jviqDH9cIqRSRpH0UxgmpT7a8CwEhs9mLHBhoYhXo8= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d h1:WtAMR0fPCOfK7TPGZ8ZpLLY18HRvL7XJ3xcs0wnREgo= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d/go.mod h1:WML6KOYjeU8N6YyusMjj2qRvaPNUEvrQvaxuFcMRFJY= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= @@ -66,8 +65,8 @@ github.com/digitalocean/godo v1.30.0 h1:4Zb+xBlKMXKg772eyQk6px3sk9RhWj/CR75tQ375 github.com/digitalocean/godo v1.30.0/go.mod h1:iJnN9rVu6K5LioLxLimlq0uRI+y/eAQjROUmeU/r0hY= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c h1:Llo2tjvv1SspjFXiM8NJyxirMPTZvNPk3lLCPf61COo= -github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c/go.mod h1:0FYu4qVNv/UcfZPNwa9zi68IkggJu3TIwM54D7rhmI4= +github.com/dnsimple/dnsimple-go v0.31.0 h1:I1T+AxBQfhovyyfGSJ4CSUeH0iQejLArsUlhSQKw8WI= +github.com/dnsimple/dnsimple-go v0.31.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/exoscale/egoscale v0.10.5 h1:pV1gDCsXPi9vfbZ1TIMz7mNGEDMiVHlQlbcJp1qxIaU= diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index 272e0536f..aaa458649 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -25,7 +25,7 @@ var features = providers.DocumentationNotes{ providers.DocCreateDomains: providers.Cannot(), providers.DocDualHost: providers.Cannot("DNSimple does not allow sufficient control over the apex NS records"), providers.DocOfficiallySupported: providers.Cannot(), - providers.CanGetZones: providers.Unimplemented(), + providers.CanGetZones: providers.Can(), } func init() { @@ -56,24 +56,14 @@ func (c *DnsimpleApi) GetNameservers(domainName string) ([]*models.Nameserver, e // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (client *DnsimpleApi) GetZoneRecords(domain string) (models.Records, error) { - return nil, fmt.Errorf("not implemented") - // This enables the get-zones subcommand. - // Implement this by extracting the code from GetDomainCorrections into - // a single function. For most providers this should be relatively easy. -} - -// GetDomainCorrections returns corrections that update a domain. -func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - corrections := []*models.Correction{} - dc.Punycode() - records, err := c.getRecords(dc.Name) + records, err := client.getRecords(domain) if err != nil { return nil, err } - var actual []*models.RecordConfig + var cleanedRecords models.Records for _, r := range records { - if r.Type == "SOA" || r.Type == "NS" { + if r.Type == "SOA" { continue } if r.Name == "" { @@ -82,8 +72,8 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C if r.Type == "CNAME" || r.Type == "MX" || r.Type == "ALIAS" { r.Content += "." } - // dnsimple adds these odd txt records that mirror the alias records. - // they seem to manage them on deletes and things, so we'll just pretend they don't exist + // DNSimple adds TXT records that mirror the alias records. + // They manage them on ALIAS updates, so pretend they don't exist if r.Type == "TXT" && strings.HasPrefix(r.Content, "ALIAS for ") { continue } @@ -91,7 +81,7 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C TTL: uint32(r.TTL), Original: r, } - rec.SetLabel(r.Name, dc.Name) + rec.SetLabel(r.Name, domain) switch rtype := r.Type; rtype { case "ALIAS", "URL": rec.Type = r.Type @@ -109,12 +99,29 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C panic(fmt.Errorf("unparsable record received from dnsimple: %w", err)) } default: - if err := rec.PopulateFromString(r.Type, r.Content, dc.Name); err != nil { + if err := rec.PopulateFromString(r.Type, r.Content, domain); err != nil { panic(fmt.Errorf("unparsable record received from dnsimple: %w", err)) } } - actual = append(actual, rec) + cleanedRecords = append(cleanedRecords, rec) } + + return cleanedRecords, nil +} + +// GetDomainCorrections returns corrections that update a domain. +func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + corrections := []*models.Correction{} + err := dc.Punycode() + if err != nil { + return nil, err + } + + records, err := c.GetZoneRecords(dc.Name) + if err != nil { + return nil, err + } + actual := removeNS(records) removeOtherNS(dc) // Normalize @@ -151,6 +158,16 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C return corrections, nil } +func removeNS(records models.Records) models.Records { + var noNameServers models.Records + for _, r := range records { + if r.Type != "NS" { + noNameServers = append(noNameServers, r) + } + } + return noNameServers +} + // GetRegistrarCorrections returns corrections that update a domain's registrar. func (c *DnsimpleApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { corrections := []*models.Correction{} @@ -360,6 +377,34 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R } } +// Returns all the zones in an account +func (c *DnsimpleApi) ListZones() ([]string, error) { + client := c.getClient() + accountID, err := c.getAccountID() + if err != nil { + return nil, err + } + + var zones []string + opts := &dnsimpleapi.ZoneListOptions{} + opts.Page = 1 + for { + zonesResponse, err := client.Zones.ListZones(accountID, opts) + if err != nil { + return nil, err + } + for _, zone := range zonesResponse.Data { + zones = append(zones, zone.Name) + } + pg := zonesResponse.Pagination + if pg.CurrentPage == pg.TotalPages { + break + } + opts.Page++ + } + return zones, nil +} + // constructors func newReg(conf map[string]string) (providers.Registrar, error) { diff --git a/vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt b/vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt index 3c2f300e1..0a39bd177 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt +++ b/vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2018 Aetrion LLC dba DNSimple +Copyright (c) 2014-2020 DNSimple Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go index 0c15b48e2..20878ef15 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go +++ b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go @@ -23,7 +23,7 @@ const ( // This is a pro-forma convention given that Go dependencies // tends to be fetched directly from the repo. // It is also used in the user-agent identify the client. - Version = "0.20.0" + Version = "0.31.0" // defaultBaseURL to the DNSimple production API. defaultBaseURL = "https://api.dnsimple.com" @@ -146,7 +146,7 @@ func formatUserAgent(customUserAgent string) string { return defaultUserAgent } - return fmt.Sprintf("%s %s", defaultUserAgent, customUserAgent) + return fmt.Sprintf("%s %s", customUserAgent, defaultUserAgent) } func versioned(path string) string { diff --git a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go index 6cd8fd7fb..8ca687144 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go +++ b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go @@ -129,18 +129,10 @@ func (s *DomainsService) DeleteDomain(accountID string, domainIdentifier string) return domainResponse, nil } -// ResetDomainToken resets the domain token. +// DEPRECATED // // See https://developer.dnsimple.com/v2/domains/#reset-token func (s *DomainsService) ResetDomainToken(accountID string, domainIdentifier string) (*domainResponse, error) { - path := versioned(domainPath(accountID, domainIdentifier) + "/token") - domainResponse := &domainResponse{} - - resp, err := s.client.post(path, nil, domainResponse) - if err != nil { - return nil, err - } - - domainResponse.HttpResponse = resp - return domainResponse, nil + // noop + return &domainResponse{}, nil } diff --git a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go index 625bbb2dc..1013bd607 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go +++ b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go @@ -62,7 +62,7 @@ type DomainPremiumPriceOptions struct { Action string `url:"action,omitempty"` } -// Gets the premium price for a domain. +// GetDomainPremiumPrice gets the premium price for a domain. // // You must specify an action to get the price for. Valid actions are: // - registration diff --git a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go index edf47b12a..730fd8a44 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go +++ b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go @@ -14,12 +14,30 @@ type WhoisPrivacy struct { UpdatedAt string `json:"updated_at,omitempty"` } +// WhoisPrivacyRenewal represents a whois privacy renewal in DNSimple. +type WhoisPrivacyRenewal struct { + ID int64 `json:"id,omitempty"` + DomainID int64 `json:"domain_id,omitempty"` + WhoisPrivacyID int64 `json:"whois_privacy_id,omitempty"` + State string `json:"string,omitempty"` + Enabled bool `json:"enabled,omitempty"` + ExpiresOn string `json:"expires_on,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` +} + // whoisPrivacyResponse represents a response from an API method that returns a WhoisPrivacy struct. type whoisPrivacyResponse struct { Response Data *WhoisPrivacy `json:"data"` } +// whoisPrivacyRenewalResponse represents a response from an API method that returns a WhoisPrivacyRenewal struct. +type whoisPrivacyRenewalResponse struct { + Response + Data *WhoisPrivacyRenewal `json:"data"` +} + // GetWhoisPrivacy gets the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#get @@ -52,7 +70,7 @@ func (s *RegistrarService) EnableWhoisPrivacy(accountID string, domainName strin return privacyResponse, nil } -// DisablePrivacy disables the whois privacy for the domain. +// DisableWhoisPrivacy disables the whois privacy for the domain. // // See https://developer.dnsimple.com/v2/registrar/whois-privacy/#enable func (s *RegistrarService) DisableWhoisPrivacy(accountID string, domainName string) (*whoisPrivacyResponse, error) { @@ -67,3 +85,19 @@ func (s *RegistrarService) DisableWhoisPrivacy(accountID string, domainName stri privacyResponse.HttpResponse = resp return privacyResponse, nil } + +// RenewWhoisPrivacy renews the whois privacy for the domain. +// +// See https://developer.dnsimple.com/v2/registrar/whois-privacy/#renew +func (s *RegistrarService) RenewWhoisPrivacy(accountID string, domainName string) (*whoisPrivacyRenewalResponse, error) { + path := versioned(fmt.Sprintf("/%v/registrar/domains/%v/whois_privacy/renewals", accountID, domainName)) + privacyRenewalResponse := &whoisPrivacyRenewalResponse{} + + resp, err := s.client.post(path, nil, privacyRenewalResponse) + if err != nil { + return nil, err + } + + privacyRenewalResponse.HttpResponse = resp + return privacyRenewalResponse, nil +} diff --git a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go index ee0da04fe..9c5c250dd 100644 --- a/vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go +++ b/vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go @@ -100,7 +100,7 @@ func (s *TldsService) GetTld(tld string) (*tldResponse, error) { return tldResponse, nil } -// GetTld fetches the extended attributes of a TLD. +// GetTldExtendedAttributes fetches the extended attributes of a TLD. // // See https://developer.dnsimple.com/v2/tlds/#get func (s *TldsService) GetTldExtendedAttributes(tld string) (*tldExtendedAttributesResponse, error) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 1aecb8216..c97ae15f4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -77,7 +77,7 @@ github.com/dgrijalva/jwt-go github.com/digitalocean/godo # github.com/dimchansky/utfbom v1.1.0 github.com/dimchansky/utfbom -# github.com/dnsimple/dnsimple-go v0.20.1-0.20181001130357-234ec949d37c +# github.com/dnsimple/dnsimple-go v0.31.0 github.com/dnsimple/dnsimple-go/dnsimple # github.com/exoscale/egoscale v0.10.5 github.com/exoscale/egoscale