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:
@ -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>
|
||||
|
@ -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
2
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
|
||||
|
5
go.sum
5
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=
|
||||
|
@ -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) {
|
||||
|
2
vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt
generated
vendored
2
vendor/github.com/dnsimple/dnsimple-go/LICENSE.txt
generated
vendored
@ -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
|
||||
|
4
vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go
generated
vendored
4
vendor/github.com/dnsimple/dnsimple-go/dnsimple/dnsimple.go
generated
vendored
@ -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 {
|
||||
|
14
vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go
generated
vendored
14
vendor/github.com/dnsimple/dnsimple-go/dnsimple/domains.go
generated
vendored
@ -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
|
||||
}
|
||||
|
2
vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go
generated
vendored
2
vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar.go
generated
vendored
@ -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
|
||||
|
36
vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go
generated
vendored
36
vendor/github.com/dnsimple/dnsimple-go/dnsimple/registrar_whois_privacy.go
generated
vendored
@ -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
|
||||
}
|
||||
|
2
vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go
generated
vendored
2
vendor/github.com/dnsimple/dnsimple-go/dnsimple/tlds.go
generated
vendored
@ -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
2
vendor/modules.txt
vendored
@ -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
|
||||
|
Reference in New Issue
Block a user