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

DNSimple: Implement GetZones and ListZones (#637)

* Update to latest dnsimple-go

* Implement GetZoneRecords

* Better naming

* Return NS records in GetZoneRecords

* Be clearer with the comment.

As an employee I confirm this is exactly how this works. No guessing needed.

* Respect that Puncycode encoding can blow up

* Implement ListZones and the ZoneLister Interface

* Categorize DNSIMPLE

* Update docs with go generate

* vendor modules

* Don't store intermediary Zone data
This commit is contained in:
Amelia Aronsohn
2020-02-20 11:52:19 -08:00
committed by GitHub
parent ca99517ced
commit b45c6b6b6c
12 changed files with 115 additions and 45 deletions

View File

@ -922,8 +922,8 @@
<td class="success">
<i class="fa fa-check text-success" aria-hidden="true"></i>
</td>
<td class="info">
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
<td class="success">
<i class="fa fa-check text-success" aria-hidden="true"></i>
</td>
<td class="info">
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>

View File

@ -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,

2
go.mod
View File

@ -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

5
go.sum
View File

@ -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=

View File

@ -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) {

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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) {

2
vendor/modules.txt vendored
View File

@ -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