From 489be2e3dc74c84369389e92616046c67f29d1a1 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 2 May 2023 13:04:59 -0400 Subject: [PATCH] ROUTE53: fix R53_ZONE() handling for domains (#2306) Co-authored-by: Tom Limoncelli --- commands/getZones.go | 2 +- commands/previewPush.go | 5 ++- documentation/providers/bind.md | 6 +-- documentation/providers/route53.md | 24 ++++++++++ integrationTest/integration_test.go | 3 +- models/domain.go | 45 ++++++++++++++++++- models/provider.go | 2 +- pkg/normalize/validate.go | 32 +++---------- pkg/zonerecs/zonerecords.go | 3 +- .../akamaiedgedns/akamaiEdgeDnsProvider.go | 2 +- providers/autodns/autoDnsProvider.go | 2 +- providers/axfrddns/axfrddnsProvider.go | 2 +- providers/azuredns/azureDnsProvider.go | 2 +- providers/bind/bindProvider.go | 7 ++- providers/bind/fnames.go | 2 + providers/cloudflare/cloudflareProvider.go | 2 +- providers/cloudns/cloudnsProvider.go | 2 +- providers/cscglobal/dns.go | 2 +- providers/desec/desecProvider.go | 2 +- .../digitalocean/digitaloceanProvider.go | 2 +- providers/dnsimple/dnsimpleProvider.go | 2 +- providers/dnsmadeeasy/dnsMadeEasyProvider.go | 2 +- providers/domainnameshop/dns.go | 2 +- providers/exoscale/exoscaleProvider.go | 2 +- providers/gandiv5/gandi_v5Provider.go | 2 +- providers/gcloud/gcloudProvider.go | 2 +- providers/gcore/gcoreProvider.go | 2 +- providers/hedns/hednsProvider.go | 2 +- providers/hetzner/hetznerProvider.go | 2 +- providers/hexonet/records.go | 2 +- providers/hostingde/hostingdeProvider.go | 2 +- providers/inwx/inwxProvider.go | 2 +- providers/linode/linodeProvider.go | 2 +- providers/loopia/loopiaProvider.go | 2 +- providers/luadns/luadnsProvider.go | 2 +- providers/msdns/msdnsProvider.go | 2 +- providers/namecheap/namecheapProvider.go | 2 +- providers/namedotcom/records.go | 2 +- providers/netcup/netcupProvider.go | 2 +- providers/netlify/netlifyProvider.go | 2 +- providers/ns1/ns1Provider.go | 2 +- providers/oracle/oracleProvider.go | 2 +- providers/ovh/ovhProvider.go | 2 +- providers/packetframe/packetframeProvider.go | 2 +- providers/porkbun/porkbunProvider.go | 2 +- providers/powerdns/dns.go | 2 +- providers/providers.go | 2 +- providers/route53/route53Provider.go | 19 ++++++-- providers/rwth/dns.go | 2 +- providers/softlayer/softlayerProvider.go | 2 +- providers/transip/transipProvider.go | 2 +- providers/vultr/vultrProvider.go | 12 ++--- 52 files changed, 151 insertions(+), 89 deletions(-) diff --git a/commands/getZones.go b/commands/getZones.go index 9be04e084..3a09c5264 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -200,7 +200,7 @@ func GetZone(args GetZoneArgs) error { // fetch all of the records zoneRecs := make([]models.Records, len(zones)) for i, zone := range zones { - recs, err := provider.GetZoneRecords(zone) + recs, err := provider.GetZoneRecords(zone, nil) if err != nil { return fmt.Errorf("failed GetZone gzr: %w", err) } diff --git a/commands/previewPush.go b/commands/previewPush.go index e47fcada8..c4ae92d4f 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -160,7 +160,8 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { func(domain *models.DomainConfig) { defer wg.Done() // defer notify WaitGroup this anonymous function has finished - if !args.shouldRunDomain(domain.UniqueName) { + uniquename := domain.GetUniqueName() + if !args.shouldRunDomain(uniquename) { return } @@ -171,7 +172,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error { // Correct the domain... - out.StartDomain(domain.UniqueName) + out.StartDomain(uniquename) var providersWithExistingZone []*models.DNSProviderInstance /// For each DSP... for _, provider := range domain.DNSProviderInstances { diff --git a/documentation/providers/bind.md b/documentation/providers/bind.md index a2347001d..95174dbd6 100644 --- a/documentation/providers/bind.md +++ b/documentation/providers/bind.md @@ -90,8 +90,8 @@ file name is the name as specified in the `D()` function plus ".zone". The filenameformat is a string with a few printf-like `%` verbs: * `%U` the domain name as specified in `D()` - * `%D` the domain name without any split horizon tag - * `%T` the split horizon tag, or "", see `D()` + * `%D` the domain name without any split horizon tag (the "example.com" part of "example.com!tag") + * `%T` the split horizon tag, or "" (the "tag" part of "example.com!tag") * `%?x` this returns `x` if the split horizon tag is non-null, otherwise nothing. `x` can be any printable. * `%%` `%` * ordinary characters (not `%`) are copied unchanged to the output stream @@ -111,7 +111,7 @@ Typical values: The last example will generate the same name for both `D("example.tld!inside")` and `D("example.tld!outside")`. This -assumes two BIND providers are configured in `creds.json`, eacch with +assumes two BIND providers are configured in `creds.json`, each with a different `directory` setting. Otherwise `dnscontrol` will write both domains to the same file, flapping between the two back and forth. diff --git a/documentation/providers/route53.md b/documentation/providers/route53.md index 805f724fb..ac0a3730d 100644 --- a/documentation/providers/route53.md +++ b/documentation/providers/route53.md @@ -78,6 +78,30 @@ D("example.tld", REG_NONE, DnsProvider(DSP_R53), ``` {% endcode %} +## Split horizon + +This provider supports spilt horizons using the `R53_ZONE()` domain function. + +In this example the domain `testzone.net` appears in the same account twice, +each with different zone IDs specified using `R53_ZONE()`. + +``` +var DSP_R53 = NewDnsProvider("r53_main"); +var REG_NONE = NewRegistrar("none"); + +D('testzone.net!private', REG_NONE, + DnsProvider(DSP_R53), + R53_ZONE('Z111111111JCCCP1V7UW'), + TXT('me', 'private testzone.net'), +); + +D('testzone.net!public', REG_NONE, + DnsProvider(DSP_R53), + R53_ZONE('Z222222222INNG98SHJQ2'), + TXT('me', 'public testzone.net'), +); +``` + ## Activation DNSControl depends on a standard [AWS access key](https://aws.amazon.com/developers/access-keys/) with permission to list, create and update hosted zones. If you do not have the permissions required you will receive the following error message `Check your credentials, your not authorized to perform actions on Route 53 AWS Service`. diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index de6eadc26..9ead16081 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -14,7 +14,6 @@ import ( "github.com/StackExchange/dnscontrol/v3/pkg/credsfile" "github.com/StackExchange/dnscontrol/v3/pkg/diff2" "github.com/StackExchange/dnscontrol/v3/pkg/nameservers" - "github.com/StackExchange/dnscontrol/v3/pkg/normalize" "github.com/StackExchange/dnscontrol/v3/pkg/zonerecs" "github.com/StackExchange/dnscontrol/v3/providers" _ "github.com/StackExchange/dnscontrol/v3/providers/_all" @@ -112,7 +111,7 @@ func getDomainConfigWithNameservers(t *testing.T, prv providers.DNSServiceProvid dc := &models.DomainConfig{ Name: domainName, } - normalize.UpdateNameSplitHorizon(dc) + dc.UpdateSplitHorizonNames() // fix up nameservers ns, err := prv.GetNameservers(domainName) diff --git a/models/domain.go b/models/domain.go index 136d746f0..ebabe9127 100644 --- a/models/domain.go +++ b/models/domain.go @@ -2,19 +2,25 @@ package models import ( "fmt" + "strings" "github.com/qdm12/reprint" "golang.org/x/net/idna" ) +const ( + DOMAIN_UNIQUENAME = "dnscontrol_uniquename" + DOMAIN_TAG = "dnscontrol_tag" +) + // DomainConfig describes a DNS domain (technically a DNS zone). type DomainConfig struct { Name string `json:"name"` // NO trailing "." - Tag string `json:"-"` // split horizon tag - UniqueName string `json:"-"` // .Name + "!" + .Tag RegistrarName string `json:"registrar"` DNSProviderNames map[string]int `json:"dnsProviders"` + // Metadata[DOMAIN_UNIQUENAME] // .Name + "!" + .Tag + // Metadata[DOMAIN_TAG] // split horizon tag Metadata map[string]string `json:"meta,omitempty"` Records Records `json:"records"` Nameservers []*Nameserver `json:"nameservers,omitempty"` @@ -38,6 +44,41 @@ type DomainConfig struct { DNSProviderInstances []*DNSProviderInstance `json:"-"` } +// GetSplitHorizonNames returns the domain's name, uniquename, and tag. +func (dc *DomainConfig) GetSplitHorizonNames() (name, uniquename, tag string) { + return dc.Name, dc.Metadata[DOMAIN_UNIQUENAME], dc.Metadata[DOMAIN_TAG] +} + +// GetUniqueName returns the domain's uniquename. +func (dc *DomainConfig) GetUniqueName() (uniquename string) { + return dc.Metadata[DOMAIN_UNIQUENAME] +} + +// UpdateSplitHorizonNames updates the split horizon fields +// (uniquename and tag) based on name. +func (dc *DomainConfig) UpdateSplitHorizonNames() { + name, unique, tag := dc.GetSplitHorizonNames() + + if unique == "" { + unique = name + } + + if tag == "" { + l := strings.SplitN(name, "!", 2) + if len(l) == 2 { + name = l[0] + tag = l[1] + } + } + + dc.Name = name + if dc.Metadata == nil { + dc.Metadata = map[string]string{} + } + dc.Metadata[DOMAIN_UNIQUENAME] = unique + dc.Metadata[DOMAIN_TAG] = tag +} + // Copy returns a deep copy of the DomainConfig. func (dc *DomainConfig) Copy() (*DomainConfig, error) { newDc := &DomainConfig{} diff --git a/models/provider.go b/models/provider.go index 6adbb630d..11c7453bd 100644 --- a/models/provider.go +++ b/models/provider.go @@ -3,7 +3,7 @@ package models // DNSProvider is an interface for DNS Provider plug-ins. type DNSProvider interface { GetNameservers(domain string) ([]*Nameserver, error) - GetZoneRecords(domain string) (Records, error) + GetZoneRecords(domain string, meta map[string]string) (Records, error) GetZoneRecordsCorrections(dc *DomainConfig, existing Records) ([]*Correction, error) } diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 98b97a881..86baa1da4 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -514,48 +514,26 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { return errs } -// UpdateNameSplitHorizon fills in the split horizon fields. -func UpdateNameSplitHorizon(dc *models.DomainConfig) { - if dc.UniqueName == "" { - dc.UniqueName = dc.Name - } - if dc.Tag == "" { - l := strings.SplitN(dc.Name, "!", 2) - if len(l) == 2 { - dc.Name = l[0] - dc.Tag = l[1] - } - } -} - // processSplitHorizonDomains finds "domain.tld!tag" domains and pre-processes them. func processSplitHorizonDomains(config *models.DNSConfig) error { // Parse out names and tags. for _, d := range config.Domains { - UpdateNameSplitHorizon(d) + d.UpdateSplitHorizonNames() } // Verify uniquenames are unique seen := map[string]bool{} for _, d := range config.Domains { - if seen[d.UniqueName] { - return fmt.Errorf("duplicate domain name: %q", d.UniqueName) + uniquename := d.GetUniqueName() + if seen[uniquename] { + return fmt.Errorf("duplicate domain name: %q", uniquename) } - seen[d.UniqueName] = true + seen[uniquename] = true } return nil } -//// parseDomainSpec parses "domain.tld!tag" into its component parts. -//func parseDomainSpec(s string) (domain, tag string) { -// l := strings.SplitN(s, "!", 2) -// if len(l) == 2 { -// return l[0], l[1] -// } -// return l[0], "" -//} - func checkAutoDNSSEC(dc *models.DomainConfig) (errs []error) { if strings.ToLower(dc.RegistrarName) == "none" { return diff --git a/pkg/zonerecs/zonerecords.go b/pkg/zonerecs/zonerecords.go index 4a1cb46ae..e56b92252 100644 --- a/pkg/zonerecs/zonerecords.go +++ b/pkg/zonerecs/zonerecords.go @@ -8,7 +8,8 @@ import ( // post-processing, and then calls GetZoneRecordsCorrections. The // name sucks because all the good names were taken. func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*models.Correction, error) { - existingRecords, err := driver.GetZoneRecords(dc.Name) + + existingRecords, err := driver.GetZoneRecords(dc.Name, dc.Metadata) if err != nil { return nil, err } diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go index 055f38261..b197e32e0 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go @@ -224,7 +224,7 @@ func (a *edgeDNSProvider) GetNameservers(domain string) ([]*models.Nameserver, e } // GetZoneRecords returns an array of RecordConfig structs for a zone. -func (a *edgeDNSProvider) GetZoneRecords(domain string) (models.Records, error) { +func (a *edgeDNSProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := getRecords(domain) if err != nil { return nil, err diff --git a/providers/autodns/autoDnsProvider.go b/providers/autodns/autoDnsProvider.go index 210e79e41..af21496d5 100644 --- a/providers/autodns/autoDnsProvider.go +++ b/providers/autodns/autoDnsProvider.go @@ -254,7 +254,7 @@ func (api *autoDNSProvider) GetNameservers(domain string) ([]*models.Nameserver, } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *autoDNSProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *autoDNSProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, _ := api.getZone(domain) existingRecords := make([]*models.RecordConfig, len(zone.ResourceRecords)) for i, resourceRecord := range zone.ResourceRecords { diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index 6a75f42d8..e3ab8ecb1 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -271,7 +271,7 @@ func (c *axfrddnsProvider) FetchZoneRecords(domain string) ([]dns.RR, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *axfrddnsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *axfrddnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { rawRecords, err := c.FetchZoneRecords(domain) if err != nil { diff --git a/providers/azuredns/azureDnsProvider.go b/providers/azuredns/azureDnsProvider.go index cdddb9ada..ca37fa9ac 100644 --- a/providers/azuredns/azureDnsProvider.go +++ b/providers/azuredns/azureDnsProvider.go @@ -161,7 +161,7 @@ func (a *azurednsProvider) ListZones() ([]string, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (a *azurednsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (a *azurednsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { existingRecords, _, _, err := a.getExistingRecords(domain) if err != nil { return nil, err diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 08bc7e70d..a651f4b03 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -153,7 +153,7 @@ func (c *bindProvider) ListZones() ([]string, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *bindProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *bindProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { if _, err := os.Stat(c.directory); os.IsNotExist(err) { printer.Printf("\nWARNING: BIND directory %q does not exist!\n", c.directory) @@ -162,6 +162,7 @@ func (c *bindProvider) GetZoneRecords(domain string) (models.Records, error) { if c.zonefile == "" { // This layering violation is needed for tests only. // Otherwise, this is set already. + // Note: In this situation there is no "uniquename" or "tag". c.zonefile = filepath.Join(c.directory, makeFileName(c.filenameformat, domain, domain, "")) } @@ -297,7 +298,9 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR } c.zonefile = filepath.Join(c.directory, - makeFileName(c.filenameformat, dc.Name, dc.Name, "")) + makeFileName(c.filenameformat, + dc.Metadata[models.DOMAIN_UNIQUENAME], dc.Name, dc.Metadata[models.DOMAIN_TAG]), + ) // We only change the serial number if there is a change. if !c.skipNextSoaIncrease { diff --git a/providers/bind/fnames.go b/providers/bind/fnames.go index 108e5ca04..0803174a8 100644 --- a/providers/bind/fnames.go +++ b/providers/bind/fnames.go @@ -11,6 +11,7 @@ import ( // makeFileName uses format to generate a zone's filename. See the func makeFileName(format, uniquename, domain, tag string) string { + //fmt.Printf("DEBUG: makeFileName(%q, %q, %q, %q)\n", format, uniquename, domain, tag) if format == "" { fmt.Fprintf(os.Stderr, "BUG: makeFileName called with null format\n") return uniquename @@ -55,6 +56,7 @@ func makeFileName(format, uniquename, domain, tag string) string { } } + //fmt.Printf("DEBUG: makeFileName returns= %q\n", b.String()) return b.String() } diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 179c4e94d..21d83957f 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -109,7 +109,7 @@ func (c *cloudflareProvider) ListZones() ([]string, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *cloudflareProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { domainID, err := c.getDomainID(domain) if err != nil { diff --git a/providers/cloudns/cloudnsProvider.go b/providers/cloudns/cloudnsProvider.go index 5e5f8dc22..69bb04c21 100644 --- a/providers/cloudns/cloudnsProvider.go +++ b/providers/cloudns/cloudnsProvider.go @@ -226,7 +226,7 @@ func (c *cloudnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *cloudnsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *cloudnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := c.getRecords(domain) if err != nil { return nil, err diff --git a/providers/cscglobal/dns.go b/providers/cscglobal/dns.go index 6a18b141c..f2a66e6fa 100644 --- a/providers/cscglobal/dns.go +++ b/providers/cscglobal/dns.go @@ -9,7 +9,7 @@ import ( ) // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (client *providerClient) GetZoneRecords(domain string) (models.Records, error) { +func (client *providerClient) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := client.getZoneRecordsAll(domain) if err != nil { return nil, err diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index 7a946c601..f22606e4d 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -98,7 +98,7 @@ func (c *desecProvider) GetNameservers(domain string) ([]*models.Nameserver, err // } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *desecProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *desecProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := c.getRecords(domain) if err != nil { return nil, err diff --git a/providers/digitalocean/digitaloceanProvider.go b/providers/digitalocean/digitaloceanProvider.go index 17ced7754..4ce70e66b 100644 --- a/providers/digitalocean/digitaloceanProvider.go +++ b/providers/digitalocean/digitaloceanProvider.go @@ -115,7 +115,7 @@ func (api *digitaloceanProvider) GetNameservers(domain string) ([]*models.Namese } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *digitaloceanProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *digitaloceanProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := getRecords(api, domain) if err != nil { return nil, err diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index 4c9100b00..93fa52068 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -75,7 +75,7 @@ func (c *dnsimpleProvider) GetNameservers(_ string) ([]*models.Nameserver, error } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *dnsimpleProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *dnsimpleProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := c.getRecords(domain) if err != nil { return nil, err diff --git a/providers/dnsmadeeasy/dnsMadeEasyProvider.go b/providers/dnsmadeeasy/dnsMadeEasyProvider.go index e191dbd9a..27f3c1375 100644 --- a/providers/dnsmadeeasy/dnsMadeEasyProvider.go +++ b/providers/dnsmadeeasy/dnsMadeEasyProvider.go @@ -218,7 +218,7 @@ func (api *dnsMadeEasyProvider) GetNameservers(domain string) ([]*models.Nameser } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *dnsMadeEasyProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *dnsMadeEasyProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := api.fetchDomainRecords(domain) if err != nil { return nil, err diff --git a/providers/domainnameshop/dns.go b/providers/domainnameshop/dns.go index 0a6d85759..a00978b0c 100644 --- a/providers/domainnameshop/dns.go +++ b/providers/domainnameshop/dns.go @@ -10,7 +10,7 @@ import ( "github.com/StackExchange/dnscontrol/v3/pkg/diff2" ) -func (api *domainNameShopProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *domainNameShopProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := api.getDNS(domain) if err != nil { return nil, err diff --git a/providers/exoscale/exoscaleProvider.go b/providers/exoscale/exoscaleProvider.go index 658ab6d98..2e73823df 100644 --- a/providers/exoscale/exoscaleProvider.go +++ b/providers/exoscale/exoscaleProvider.go @@ -88,7 +88,7 @@ func (c *exoscaleProvider) GetNameservers(domain string) ([]*models.Nameserver, } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *exoscaleProvider) GetZoneRecords(domainName string) (models.Records, error) { +func (c *exoscaleProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) { //dc.Punycode() domain, err := c.findDomainByName(domainName) diff --git a/providers/gandiv5/gandi_v5Provider.go b/providers/gandiv5/gandi_v5Provider.go index b60d15b56..4b197e086 100644 --- a/providers/gandiv5/gandi_v5Provider.go +++ b/providers/gandiv5/gandi_v5Provider.go @@ -129,7 +129,7 @@ func newHelper(m map[string]string, metadata json.RawMessage) (*gandiv5Provider, // GetZoneRecords gathers the DNS records and converts them to // dnscontrol's format. -func (client *gandiv5Provider) GetZoneRecords(domain string) (models.Records, error) { +func (client *gandiv5Provider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { g := gandi.NewLiveDNSClient(config.Config{ APIKey: client.apikey, SharingID: client.sharingid, diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index 4b5244249..f880e92f6 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -172,7 +172,7 @@ func keyForRec(r *models.RecordConfig) key { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (g *gcloudProvider) GetZoneRecords(domain string) (models.Records, error) { +func (g *gcloudProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { existingRecords, err := g.getZoneSets(domain) return existingRecords, err } diff --git a/providers/gcore/gcoreProvider.go b/providers/gcore/gcoreProvider.go index 760059f1d..ab69f8538 100644 --- a/providers/gcore/gcoreProvider.go +++ b/providers/gcore/gcoreProvider.go @@ -77,7 +77,7 @@ func (c *gcoreProvider) GetNameservers(domain string) ([]*models.Nameserver, err } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *gcoreProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *gcoreProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, err := c.provider.Zone(c.ctx, domain) if err != nil { return nil, err diff --git a/providers/hedns/hednsProvider.go b/providers/hedns/hednsProvider.go index 021b04dc5..8602376af 100644 --- a/providers/hedns/hednsProvider.go +++ b/providers/hedns/hednsProvider.go @@ -284,7 +284,7 @@ func (c *hednsProvider) getDiff2DomainCorrections(dc *models.DomainConfig, zoneI } // GetZoneRecords returns all the records for the given domain -func (c *hednsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *hednsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { var zoneRecords []*models.RecordConfig // Get Domain ID diff --git a/providers/hetzner/hetznerProvider.go b/providers/hetzner/hetznerProvider.go index 20a4a5854..347420566 100644 --- a/providers/hetzner/hetznerProvider.go +++ b/providers/hetzner/hetznerProvider.go @@ -154,7 +154,7 @@ func (api *hetznerProvider) GetNameservers(domain string) ([]*models.Nameserver, } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *hetznerProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *hetznerProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := api.getAllRecords(domain) if err != nil { return nil, err diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index f974e84cd..f66f4f05c 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -37,7 +37,7 @@ type HXRecord struct { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n *HXClient) GetZoneRecords(domain string) (models.Records, error) { +func (n *HXClient) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := n.getRecords(domain) if err != nil { return nil, err diff --git a/providers/hostingde/hostingdeProvider.go b/providers/hostingde/hostingdeProvider.go index 8b68846ed..af38a9d0c 100644 --- a/providers/hostingde/hostingdeProvider.go +++ b/providers/hostingde/hostingdeProvider.go @@ -93,7 +93,7 @@ func (hp *hostingdeProvider) GetNameservers(domain string) ([]*models.Nameserver return models.ToNameservers(hp.nameservers) } -func (hp *hostingdeProvider) GetZoneRecords(domain string) (models.Records, error) { +func (hp *hostingdeProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, err := hp.getZone(domain) if err != nil { return nil, err diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 401ee853b..dc54267fe 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -288,7 +288,7 @@ func (api *inwxAPI) GetNameservers(domain string) ([]*models.Nameserver, error) } // GetZoneRecords receives the current records from Inwx and converts them to models.RecordConfig. -func (api *inwxAPI) GetZoneRecords(domain string) (models.Records, error) { +func (api *inwxAPI) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { info, err := api.client.Nameservers.Info(&goinwx.NameserverInfoRequest{Domain: domain}) if err != nil { return nil, err diff --git a/providers/linode/linodeProvider.go b/providers/linode/linodeProvider.go index ad5fd6ce0..16305211c 100644 --- a/providers/linode/linodeProvider.go +++ b/providers/linode/linodeProvider.go @@ -108,7 +108,7 @@ func (api *linodeProvider) GetNameservers(domain string) ([]*models.Nameserver, } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *linodeProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *linodeProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { if api.domainIndex == nil { if err := api.fetchDomainList(); err != nil { return nil, err diff --git a/providers/loopia/loopiaProvider.go b/providers/loopia/loopiaProvider.go index e3313841b..556016482 100644 --- a/providers/loopia/loopiaProvider.go +++ b/providers/loopia/loopiaProvider.go @@ -158,7 +158,7 @@ func (c *APIClient) ListZones() ([]string, error) { // GetZoneRecords gathers the DNS records and converts them to // dnscontrol's format. -func (c *APIClient) GetZoneRecords(domain string) (models.Records, error) { +func (c *APIClient) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { // Two approaches. One: get all SubDomains, and get their respective records // simultaneously, or first get subdomains then fill each subdomain with its diff --git a/providers/luadns/luadnsProvider.go b/providers/luadns/luadnsProvider.go index 46f91d8db..90da43d68 100644 --- a/providers/luadns/luadnsProvider.go +++ b/providers/luadns/luadnsProvider.go @@ -78,7 +78,7 @@ func (l *luadnsProvider) ListZones() ([]string, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (l *luadnsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (l *luadnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { domainID, err := l.getDomainID(domain) if err != nil { return nil, err diff --git a/providers/msdns/msdnsProvider.go b/providers/msdns/msdnsProvider.go index 33ffa3da6..544ef053f 100644 --- a/providers/msdns/msdnsProvider.go +++ b/providers/msdns/msdnsProvider.go @@ -71,7 +71,7 @@ func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSSe // GetZoneRecords gathers the DNS records and converts them to // dnscontrol's format. -func (client *msdnsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (client *msdnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { // Get the existing DNS records in native format. nativeExistingRecords, err := client.shell.GetDNSZoneRecords(client.dnsserver, domain) diff --git a/providers/namecheap/namecheapProvider.go b/providers/namecheap/namecheapProvider.go index 8bb6eddd8..a7d74b32c 100644 --- a/providers/namecheap/namecheapProvider.go +++ b/providers/namecheap/namecheapProvider.go @@ -114,7 +114,7 @@ func doWithRetry(f func() error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n *namecheapProvider) GetZoneRecords(domain string) (models.Records, error) { +func (n *namecheapProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { sld, tld := splitDomain(domain) var records *nc.DomainDNSGetHostsResult var err error diff --git a/providers/namedotcom/records.go b/providers/namedotcom/records.go index e9446f9be..f70bc1d23 100644 --- a/providers/namedotcom/records.go +++ b/providers/namedotcom/records.go @@ -20,7 +20,7 @@ var defaultNameservers = []*models.Nameserver{ } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n *namedotcomProvider) GetZoneRecords(domain string) (models.Records, error) { +func (n *namedotcomProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := n.getRecords(domain) if err != nil { return nil, err diff --git a/providers/netcup/netcupProvider.go b/providers/netcup/netcupProvider.go index c9085ece6..c441894a0 100644 --- a/providers/netcup/netcupProvider.go +++ b/providers/netcup/netcupProvider.go @@ -44,7 +44,7 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *netcupProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *netcupProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := api.getRecords(domain) if err != nil { return nil, err diff --git a/providers/netlify/netlifyProvider.go b/providers/netlify/netlifyProvider.go index dc31418fa..9522e8090 100644 --- a/providers/netlify/netlifyProvider.go +++ b/providers/netlify/netlifyProvider.go @@ -86,7 +86,7 @@ func (n *netlifyProvider) getZone(domain string) (*dnsZone, error) { return nil, fmt.Errorf("no zones found for this domain") } -func (n *netlifyProvider) GetZoneRecords(domain string) (models.Records, error) { +func (n *netlifyProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, err := n.getZone(domain) if err != nil { return nil, err diff --git a/providers/ns1/ns1Provider.go b/providers/ns1/ns1Provider.go index 9eda93deb..b42b2ce06 100644 --- a/providers/ns1/ns1Provider.go +++ b/providers/ns1/ns1Provider.go @@ -89,7 +89,7 @@ func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n *nsone) GetZoneRecords(domain string) (models.Records, error) { +func (n *nsone) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { z, _, err := n.Zones.Get(domain) if err != nil { return nil, err diff --git a/providers/oracle/oracleProvider.go b/providers/oracle/oracleProvider.go index 63841044f..b60077d42 100644 --- a/providers/oracle/oracleProvider.go +++ b/providers/oracle/oracleProvider.go @@ -148,7 +148,7 @@ func (o *oracleProvider) GetNameservers(domain string) ([]*models.Nameserver, er return models.ToNameservers(nss) } -func (o *oracleProvider) GetZoneRecords(zone string) (models.Records, error) { +func (o *oracleProvider) GetZoneRecords(zone string, meta map[string]string) (models.Records, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/providers/ovh/ovhProvider.go b/providers/ovh/ovhProvider.go index a2f75a1f0..cf4db7ce2 100644 --- a/providers/ovh/ovhProvider.go +++ b/providers/ovh/ovhProvider.go @@ -95,7 +95,7 @@ func (c *ovhProvider) ListZones() (zones []string, err error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *ovhProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *ovhProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { if !c.zones[domain] { return nil, errNoExist{domain} } diff --git a/providers/packetframe/packetframeProvider.go b/providers/packetframe/packetframeProvider.go index e32a6c87e..e3cc7dfb1 100644 --- a/providers/packetframe/packetframeProvider.go +++ b/providers/packetframe/packetframeProvider.go @@ -75,7 +75,7 @@ func (api *packetframeProvider) getZone(domain string) (*zoneInfo, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *packetframeProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *packetframeProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, err := api.getZone(domain) if err != nil { diff --git a/providers/porkbun/porkbunProvider.go b/providers/porkbun/porkbunProvider.go index 7011edb5b..6778229c4 100644 --- a/providers/porkbun/porkbunProvider.go +++ b/providers/porkbun/porkbunProvider.go @@ -191,7 +191,7 @@ func (c *porkbunProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *porkbunProvider) GetZoneRecords(domain string) (models.Records, error) { +func (c *porkbunProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := c.getRecords(domain) if err != nil { return nil, err diff --git a/providers/powerdns/dns.go b/providers/powerdns/dns.go index c3878a550..580144093 100644 --- a/providers/powerdns/dns.go +++ b/providers/powerdns/dns.go @@ -20,7 +20,7 @@ func (dsp *powerdnsProvider) GetNameservers(string) ([]*models.Nameserver, error } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (dsp *powerdnsProvider) GetZoneRecords(domain string) (models.Records, error) { +func (dsp *powerdnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { zone, err := dsp.client.Zones().GetZone(context.Background(), dsp.ServerName, domain) if err != nil { return nil, err diff --git a/providers/providers.go b/providers/providers.go index d8e8a47c1..ae1fb5f78 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -157,7 +157,7 @@ func (n None) GetNameservers(string) ([]*models.Nameserver, error) { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n None) GetZoneRecords(domain string) (models.Records, error) { +func (n None) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { return nil, nil } diff --git a/providers/route53/route53Provider.go b/providers/route53/route53Provider.go index 18f5ff2b9..792e8d03f 100644 --- a/providers/route53/route53Provider.go +++ b/providers/route53/route53Provider.go @@ -134,7 +134,6 @@ func (r *route53Provider) ListZones() ([]string, error) { } func (r *route53Provider) getZones() error { - // TODO(tlim) This should memoize itself. if r.zonesByDomain != nil { return nil @@ -212,20 +211,34 @@ func (r *route53Provider) GetNameservers(domain string) ([]*models.Nameserver, e return models.ToNameservers(nss) } -func (r *route53Provider) GetZoneRecords(domain string) (models.Records, error) { +func (r *route53Provider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { if err := r.getZones(); err != nil { return nil, err } + var zone r53Types.HostedZone + + // If the zone_id is specified in meta, use it. + if zoneID, ok := meta["zone_id"]; ok { + zone = r.zonesByID[zoneID] + return r.getZoneRecords(zone) + } + + // fmt.Printf("DEBUG: ROUTE53 zones:\n") + // for i, j := range r.zonesByDomain { + // fmt.Printf(" %s: %v\n", i, aws.ToString(j.Id)) + // } + + // Otherwise, use the domain name to look up the zone. if zone, ok := r.zonesByDomain[domain]; ok { return r.getZoneRecords(zone) } + // Not found there? Error. return nil, errDomainNoExist{domain} } func (r *route53Provider) getZone(dc *models.DomainConfig) (r53Types.HostedZone, error) { - // TODO(tlim) This should memoize itself. if err := r.getZones(); err != nil { return r53Types.HostedZone{}, err diff --git a/providers/rwth/dns.go b/providers/rwth/dns.go index 825839569..dd3d67009 100644 --- a/providers/rwth/dns.go +++ b/providers/rwth/dns.go @@ -13,7 +13,7 @@ import ( var RWTHDefaultNs = []string{"dns-1.dfn.de", "dns-2.dfn.de", "zs1.rz.rwth-aachen.de", "zs2.rz.rwth-aachen.de"} // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *rwthProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *rwthProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { records, err := api.getAllRecords(domain) if err != nil { return nil, err diff --git a/providers/softlayer/softlayerProvider.go b/providers/softlayer/softlayerProvider.go index adcbb5b63..cf4a4bdf1 100644 --- a/providers/softlayer/softlayerProvider.go +++ b/providers/softlayer/softlayerProvider.go @@ -61,7 +61,7 @@ func (s *softlayerProvider) GetNameservers(domain string) ([]*models.Nameserver, // GetZoneRecords gets all the records for domainName and converts // them to model.RecordConfig. -func (s *softlayerProvider) GetZoneRecords(domainName string) (models.Records, error) { +func (s *softlayerProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) { domain, err := s.getDomain(&domainName) if err != nil { return nil, err diff --git a/providers/transip/transipProvider.go b/providers/transip/transipProvider.go index 9fd130eff..c058511a7 100644 --- a/providers/transip/transipProvider.go +++ b/providers/transip/transipProvider.go @@ -255,7 +255,7 @@ func canUpdateDNSEntry(desired *models.RecordConfig, existing *models.RecordConf return desired.Name == existing.Name && desired.TTL == existing.TTL && desired.Type == existing.Type } -func (n *transipProvider) GetZoneRecords(domainName string) (models.Records, error) { +func (n *transipProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) { entries, err := n.domains.GetDNSEntries(domainName) if err != nil { diff --git a/providers/vultr/vultrProvider.go b/providers/vultr/vultrProvider.go index aebf4fecd..bf74a84f9 100644 --- a/providers/vultr/vultrProvider.go +++ b/providers/vultr/vultrProvider.go @@ -76,10 +76,10 @@ func NewProvider(m map[string]string, metadata json.RawMessage) (providers.DNSSe } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (api *vultrProvider) GetZoneRecords(domain string) (models.Records, error) { +func (api *vultrProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { listOptions := &govultr.ListOptions{} - records, meta, err := api.client.DomainRecord.List(context.Background(), domain, listOptions) - curRecords := make(models.Records, meta.Total) + records, recordsMeta, err := api.client.DomainRecord.List(context.Background(), domain, listOptions) + curRecords := make(models.Records, recordsMeta.Total) nextI := 0 for { @@ -97,11 +97,11 @@ func (api *vultrProvider) GetZoneRecords(domain string) (models.Records, error) } nextI = currentI + 1 - if meta.Links.Next == "" { + if recordsMeta.Links.Next == "" { break } else { - listOptions.Cursor = meta.Links.Next - records, meta, err = api.client.DomainRecord.List(context.Background(), domain, listOptions) + listOptions.Cursor = recordsMeta.Links.Next + records, recordsMeta, err = api.client.DomainRecord.List(context.Background(), domain, listOptions) continue } }