mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
BUG: Some DNS zones are downloaded twice (#2120)
Signed-off-by: Amelia Aronsohn <squirrel@wearing.black> Co-authored-by: Tom Limoncelli <tal@whatexit.org> Co-authored-by: Grégoire Henry <hnrgrgr@users.noreply.github.com> Co-authored-by: Amelia Aronsohn <squirrel@wearing.black> Co-authored-by: Kai Schwarz <kschwarz@hexonet.net> Co-authored-by: Asif Nawaz <asif.nawaz@centralnic.com> Co-authored-by: imlonghao <git@imlonghao.com> Co-authored-by: Will Power <1619102+willpower232@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,6 @@ package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/normalize"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/notifications"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/zonerecs"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
@@ -139,6 +139,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(cfg.Domains))
|
||||
|
||||
// For each domain in dnsconfig.js...
|
||||
for _, domain := range cfg.Domains {
|
||||
// Run preview or push operations per domain as anonymous function, in preparation for the later use of goroutines.
|
||||
// For now running this code is still sequential.
|
||||
@@ -150,8 +151,16 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
return
|
||||
}
|
||||
|
||||
err = domain.Punycode()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Correct the domain...
|
||||
|
||||
out.StartDomain(domain.UniqueName)
|
||||
var providersWithExistingZone []*models.DNSProviderInstance
|
||||
/// For each DSP...
|
||||
for _, provider := range domain.DNSProviderInstances {
|
||||
if !args.NoPopulate {
|
||||
// preview run: check if zone is already there, if not print a warning
|
||||
@@ -164,8 +173,8 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
aceZoneName, _ := idna.ToASCII(domain.Name)
|
||||
|
||||
if !slices.Contains(zones, aceZoneName) {
|
||||
out.Warnf("DEBUG: zones: %v\n", zones)
|
||||
out.Warnf("DEBUG: Name: %v\n", domain.Name)
|
||||
//out.Warnf("DEBUG: zones: %v\n", zones)
|
||||
//out.Warnf("DEBUG: Name: %v\n", domain.Name)
|
||||
|
||||
out.Warnf("Zone '%s' does not exist in the '%s' profile and will be added automatically.\n", domain.Name, provider.Name)
|
||||
continue // continue with next provider, as we can not determine corrections without an existing zone
|
||||
@@ -181,6 +190,8 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
providersWithExistingZone = append(providersWithExistingZone, provider)
|
||||
}
|
||||
|
||||
// Correct the registrar...
|
||||
|
||||
nsList, err := nameservers.DetermineNameserversForProviders(domain, providersWithExistingZone)
|
||||
if err != nil {
|
||||
out.Errorf("ERROR: %s", err.Error())
|
||||
@@ -190,20 +201,14 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
nameservers.AddNSRecords(domain)
|
||||
|
||||
for _, provider := range providersWithExistingZone {
|
||||
dc, err := domain.Copy()
|
||||
if err != nil {
|
||||
out.Errorf("ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
shouldrun := args.shouldRunProvider(provider.Name, dc)
|
||||
|
||||
shouldrun := args.shouldRunProvider(provider.Name, domain)
|
||||
out.StartDNSProvider(provider.Name, !shouldrun)
|
||||
if !shouldrun {
|
||||
continue
|
||||
}
|
||||
|
||||
/// This is where we should audit?
|
||||
|
||||
corrections, err := provider.Driver.GetDomainCorrections(dc)
|
||||
corrections, err := zonerecs.CorrectZoneRecords(provider.Driver, domain)
|
||||
out.EndProvider(provider.Name, len(corrections), err)
|
||||
if err != nil {
|
||||
anyErrors = true
|
||||
@@ -212,6 +217,8 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
totalCorrections += len(corrections)
|
||||
anyErrors = printOrRunCorrections(domain.Name, provider.Name, corrections, out, push, interactive, notifier) || anyErrors
|
||||
}
|
||||
|
||||
//
|
||||
run := args.shouldRunProvider(domain.RegistrarName, domain)
|
||||
out.StartRegistrar(domain.RegistrarName, !run)
|
||||
if !run {
|
||||
@@ -221,11 +228,8 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
||||
out.Warnf("No nameservers declared; skipping registrar. Add {no_ns:'true'} to force.\n")
|
||||
return
|
||||
}
|
||||
dc, err := domain.Copy()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
corrections, err := domain.RegistrarInstance.Driver.GetRegistrarCorrections(dc)
|
||||
|
||||
corrections, err := domain.RegistrarInstance.Driver.GetRegistrarCorrections(domain)
|
||||
out.EndProvider(domain.RegistrarName, len(corrections), err)
|
||||
if err != nil {
|
||||
anyErrors = true
|
||||
|
||||
@@ -66,10 +66,12 @@ And update `creds.json` accordingly:
|
||||
```json
|
||||
{
|
||||
"axfrddns-a": {
|
||||
"TYPE": "AXFRDDNS",
|
||||
"transfer-key": "hmac-sha256:transfer-key-id:Base64EncodedSecret=",
|
||||
"update-key": "hmac-sha256:update-key-id:AnotherSecret="
|
||||
},
|
||||
"axfrddns-b": {
|
||||
"TYPE": "AXFRDDNS",
|
||||
"transfer-key": "hmac-sha512:transfer-key-id-B:SmallSecret=",
|
||||
"update-key": "hmac-sha512:update-key-id-B:YetAnotherSecret="
|
||||
}
|
||||
@@ -132,6 +134,16 @@ the following error message:
|
||||
Please consider adding default `nameservers` or an explicit `master` in `creds.json`.
|
||||
```
|
||||
|
||||
### Buggy DNS servers regarding CNAME updates
|
||||
|
||||
When modifying a CNAME record, or when replacing an A record by a
|
||||
CNAME one in a single batched DDNS update, some DNS servers
|
||||
(e.g. Knot) will incorrectly reject the update. For this particular
|
||||
case, you might set the option `buggy-cname = "yes"` in `creds.json`.
|
||||
The changes will then be split in two DDNS updates, applied
|
||||
successively by the server. This will allow Knot to successfully apply
|
||||
the changes, but you will loose the atomic-update property.
|
||||
|
||||
|
||||
## Server configuration examples
|
||||
|
||||
|
||||
@@ -14,41 +14,33 @@ you designate someone else as the maintainer). More details
|
||||
|
||||
I'll ignore all the small stuff and get to the point.
|
||||
|
||||
A provider's `GetDomainCorrections()` function is the workhorse
|
||||
of the provider. It is what gets called by `dnscontrol preview`
|
||||
A typical provider implements 3 methods and DNSControl takes care of the rest:
|
||||
|
||||
* GetZoneRecords() -- Download the list of DNS records and return them as a list of RecordConfig structs.
|
||||
* GetZoneRecordsCorrections() -- Generate a list of corrections.
|
||||
* GetNameservers() -- Query the API and return the list of parent nameservers.
|
||||
|
||||
These three functions are all that's needed for `dnscontrol preview`
|
||||
and `dnscontrol push`.
|
||||
|
||||
How does a provider's `GetDomainCorrections()` function work?
|
||||
The goal of `GetZoneRecords()` is to download all the DNS records,
|
||||
convert them to `models.RecordConfig` format, and return them as one big list
|
||||
(`models.Records`).
|
||||
|
||||
The goal of `GetDomainCorrections()` is to return a list of
|
||||
The goal of `GetZoneRecordsCorrections()` is to return a list of
|
||||
corrections. Each correction is a text string describing the change
|
||||
("Delete CNAME record foo") and a function that, if called, will
|
||||
make the change (i.e. call the API and delete record foo). Preview
|
||||
mode simply prints the text strings. `dnscontrol push` prints the
|
||||
make the change (i.e. call the API and delete record foo). `dnscontrol preview`
|
||||
simply prints the text strings. `dnscontrol push` prints the
|
||||
strings and calls the functions. Because of how Go's functions work,
|
||||
the function will have everything it needs to make the change.
|
||||
Pretty cool, eh?
|
||||
|
||||
So how does `GetDomainCorrections()` work?
|
||||
|
||||
First, some terminology: The DNS records specified in the `dnsconfig.js`
|
||||
file are called the "desired" records. The DNS records stored at
|
||||
the DNS service provider are called the "existing" records.
|
||||
|
||||
Every provider does the same basic process. The function
|
||||
`GetDomainCorrections()` is called with a list of the desired DNS
|
||||
records (`dc.Records`). It then contacts the provider's API and
|
||||
gathers the existing records. It converts the existing records into
|
||||
a list of `*models.RecordConfig`.
|
||||
|
||||
Now that it has the desired and existing records in the appropriate
|
||||
format, `differ.IncrementalDiff(existingRecords)` is called and
|
||||
does all the hard work of understanding the DNS records and figuring
|
||||
out what changes need to be made. It generates lists of adds,
|
||||
deletes, and changes.
|
||||
|
||||
`GetDomainCorrections()` then generates the list of `models.Corrections()`
|
||||
and returns. DNSControl takes care of the rest.
|
||||
Calculating the difference between existing and desired is difficult. Luckily
|
||||
the work is done for you. `GetZoneRecordsCorrections()` calls a a function in
|
||||
the `pkg/diff2` module that generates a list of changes (usually an ADD,
|
||||
CHANGE, or DELETE) that can easily be turned into the API calls mentioned
|
||||
previously.
|
||||
|
||||
So, what does all this mean?
|
||||
|
||||
@@ -61,11 +53,6 @@ If you are new to Go, there are plenty of providers you can copy
|
||||
from. In fact, many non-Go programmers
|
||||
[have learned Go by contributing to DNSControl](https://everythingsysadmin.com/2017/08/go-get-up-to-speed.html).
|
||||
|
||||
Oh, and what if the API simply requires that the entire zonefile be uploaded
|
||||
every time? We still generate the text descriptions of the changes (so that
|
||||
`dnscontrol preview` looks nice) but the functions are just no-ops, except
|
||||
for one that uploads the new zonefile.
|
||||
|
||||
Now that you understand the general process, here are the details.
|
||||
|
||||
## Step 1: General advice
|
||||
@@ -80,12 +67,44 @@ was confusing so we can update this document with advice for future
|
||||
authors (or even better, update [this document](https://github.com/StackExchange/dnscontrol/blob/master/documentation/writing-providers.md)
|
||||
yourself.)
|
||||
|
||||
## NOTE: diff2
|
||||
|
||||
We are in the process of changing how providers work. Sadly this document
|
||||
hasn't been fully updated yet.
|
||||
|
||||
We are in the process of changing all providers from using `pkg/diff` to
|
||||
`pkg/diff2`. diff2 is much easier to use as it does all the hard work for you.
|
||||
Providers are easier to write, there's less code for you to write, and fewer
|
||||
chances to make mistakes.
|
||||
|
||||
New providers only need to implement diff2. Older providers are implemented
|
||||
both ways, with a flag (`--diff2`) enabling the newer code. Soon the new code
|
||||
will become the default, then the old code will be removed.
|
||||
|
||||
The file `pkg/diff2/diff2.go` has instructions about how to use the new diff2 system.
|
||||
You can also do `grep diff2.By providers/*/*.go` to find providers that use
|
||||
the new system.
|
||||
|
||||
Each DNS provider's API is different. Some update one DNS record at a time.
|
||||
Others, the only change they permit is to upload the entire zone even if only one record changed!
|
||||
Others are somewhere in between: all records at a label must be updated at once, or all records
|
||||
in a RecordSet (the label + rType). diff2 provides functions for all of these situations:
|
||||
|
||||
diff2.ByRecord() -- Updates are done one DNS record at a time. New records are added. Changes and deletes refer to an ID assigned to the record by the provider.
|
||||
diff2.ByLabel() -- Updates are done for an entire label. Adds and changes are done by sending one or more records that will appear at that label (i.e. www.example.com). Deletes delete all records at that label.
|
||||
diff2.ByRecordSet() -- Similar to ByLabel() but updates are done on the label+type level. If www.example.com has 2 A records and 2 MX records,
|
||||
|
||||
|
||||
|
||||
|
||||
## Step 2: Pick a base provider
|
||||
|
||||
Pick a similar provider as your base. Providers basically fall
|
||||
into three general categories:
|
||||
|
||||
NOTE: diff2 changes this. For now, you can simply run `grep diff2.By providers/*/*.go` to see which
|
||||
providers use ByZone, ByLabel, ByRecord, ByRecordSet and pick a similar provider to copy from.
|
||||
|
||||
* **zone:** The API requires you to upload the entire zone every time. (BIND, NAMECHEAP).
|
||||
* **incremental-record:** The API lets you add/change/delete individual DNS records. (CLOUDFLARE, DNSIMPLE, NAMEDOTCOM, GCLOUD, HEXONET)
|
||||
* **incremental-label:** Like incremental-record, but if there are
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"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"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers/cloudflare"
|
||||
@@ -200,6 +201,12 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma
|
||||
//}
|
||||
dom.Records = append(dom.Records, &rc)
|
||||
}
|
||||
if *providerToRun == "AXFRDDNS" {
|
||||
// Bind will refuse a DDNS update when the resulting zone
|
||||
// contains a NS record without an associated address
|
||||
// records (A or AAAA)
|
||||
dom.Records = append(dom.Records, a("ns."+domainName+".", "9.8.7.6"))
|
||||
}
|
||||
dom.IgnoredNames = tst.IgnoredNames
|
||||
dom.IgnoredTargets = tst.IgnoredTargets
|
||||
models.PostProcessRecords(dom.Records)
|
||||
@@ -211,7 +218,7 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma
|
||||
}
|
||||
|
||||
// get and run corrections for first time
|
||||
corrections, err := prv.GetDomainCorrections(dom)
|
||||
corrections, err := zonerecs.CorrectZoneRecords(prv, dom)
|
||||
if err != nil {
|
||||
t.Fatal(fmt.Errorf("runTests: %w", err))
|
||||
}
|
||||
@@ -234,7 +241,7 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma
|
||||
}
|
||||
|
||||
// run a second time and expect zero corrections
|
||||
corrections, err = prv.GetDomainCorrections(dom2)
|
||||
corrections, err = zonerecs.CorrectZoneRecords(prv, dom2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -328,7 +335,8 @@ func TestDualProviders(t *testing.T) {
|
||||
// clear everything
|
||||
run := func() {
|
||||
dom, _ := dc.Copy()
|
||||
cs, err := p.GetDomainCorrections(dom)
|
||||
|
||||
cs, err := zonerecs.CorrectZoneRecords(p, dom)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -350,7 +358,7 @@ func TestDualProviders(t *testing.T) {
|
||||
run()
|
||||
// run again to make sure no corrections
|
||||
t.Log("Running again to ensure stability")
|
||||
cs, err := p.GetDomainCorrections(dc)
|
||||
cs, err := zonerecs.CorrectZoneRecords(p, dc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"master": "$AXFRDDNS_MASTER",
|
||||
"nameservers": "ns.example.com",
|
||||
"transfer-key": "$AXFRDDNS_TRANSFER_KEY",
|
||||
"update-key": "$AXFRDDNS_UPDATE_KEY"
|
||||
"update-key": "$AXFRDDNS_UPDATE_KEY",
|
||||
"buggy-cname": "$AXFRDDNS_BUGGY_CNAME"
|
||||
},
|
||||
"AZURE_DNS": {
|
||||
"ClientID": "$AZURE_DNS_CLIENT_ID",
|
||||
|
||||
@@ -4,7 +4,7 @@ package models
|
||||
type DNSProvider interface {
|
||||
GetNameservers(domain string) ([]*Nameserver, error)
|
||||
GetZoneRecords(domain string) (Records, error)
|
||||
GetDomainCorrections(dc *DomainConfig) ([]*Correction, error)
|
||||
GetZoneRecordsCorrections(dc *DomainConfig, existing Records) ([]*Correction, error)
|
||||
}
|
||||
|
||||
// Registrar is an interface for Registrar plug-ins.
|
||||
|
||||
@@ -555,6 +555,7 @@ func (recs Records) GroupedByFQDN() ([]string, map[string]Records) {
|
||||
}
|
||||
|
||||
// PostProcessRecords does any post-processing of the downloaded DNS records.
|
||||
// Deprecated. zonerecords.CorrectZoneRecords() calls Downcase directly.
|
||||
func PostProcessRecords(recs []*RecordConfig) {
|
||||
Downcase(recs)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/nameservers"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/notifications"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/zonerecs"
|
||||
"github.com/go-acme/lego/certcrypto"
|
||||
"github.com/go-acme/lego/certificate"
|
||||
"github.com/go-acme/lego/challenge"
|
||||
@@ -275,7 +276,7 @@ func (c *certManager) getCorrections(d *models.DomainConfig) ([]*models.Correcti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
corrections, err := p.Driver.GetDomainCorrections(dc)
|
||||
corrections, err := zonerecs.CorrectZoneRecords(p.Driver, dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import "github.com/StackExchange/dnscontrol/v3/models"
|
||||
// SplitSingleLongTxt finds TXT records with a single long string and splits it
|
||||
// into 255-octet chunks. This is used by providers that, when a user specifies
|
||||
// one long TXT string, split it into smaller strings behind the scenes.
|
||||
// This should be called from GetZoneRecordsCorrections().
|
||||
func SplitSingleLongTxt(records []*models.RecordConfig) {
|
||||
for _, rc := range records {
|
||||
if rc.HasFormatIdenticalToTXT() {
|
||||
|
||||
34
pkg/zonerecs/zonerecords.go
Normal file
34
pkg/zonerecs/zonerecords.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package zonerecs
|
||||
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
)
|
||||
|
||||
// CorrectZoneRecords calls both GetZoneRecords, does any
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// downcase
|
||||
models.Downcase(existingRecords)
|
||||
|
||||
// Copy dc so that any corrections code that wants to
|
||||
// modify the records may. For example, if the provider only
|
||||
// supports certain TTL values, it will adjust the ones in
|
||||
// dc.Records.
|
||||
dc, err = dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// punycode
|
||||
dc.Punycode()
|
||||
// FIXME(tlim) It is a waste to PunyCode every iteration.
|
||||
// This should be moved to where the JavaScript is processed.
|
||||
|
||||
return driver.GetZoneRecordsCorrections(dc, existingRecords)
|
||||
}
|
||||
@@ -105,26 +105,13 @@ func (a *edgeDNSProvider) EnsureZoneExists(domain string) error {
|
||||
return createZone(domain, a.contractID, a.groupID)
|
||||
}
|
||||
|
||||
// GetDomainCorrections return a list of corrections. Each correction is a text string describing the change
|
||||
// and a function that, if called, will make the change.
|
||||
// “dnscontrol preview” simply prints the text strings.
|
||||
// "dnscontrol push" prints the strings and calls the functions.
|
||||
func (a *edgeDNSProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRecords, err := getRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(existingRecords)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var keysToUpdate map[models.RecordKey][]string
|
||||
var err error
|
||||
if !diff2.EnableDiff2 {
|
||||
keysToUpdate, err = (diff.New(dc)).ChangedGroups(existingRecords)
|
||||
} else {
|
||||
|
||||
@@ -67,31 +67,12 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *autoDNSProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
var changes []*models.RecordConfig
|
||||
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
domain := dc.Name
|
||||
|
||||
// Get existing records
|
||||
existingRecords, err := api.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var changes []*models.RecordConfig
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
"github.com/fatih/color"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@@ -56,13 +57,15 @@ var features = providers.DocumentationNotes{
|
||||
|
||||
// axfrddnsProvider stores the client info for the provider.
|
||||
type axfrddnsProvider struct {
|
||||
rand *rand.Rand
|
||||
master string
|
||||
updateMode string
|
||||
transferMode string
|
||||
nameservers []*models.Nameserver
|
||||
transferKey *Key
|
||||
updateKey *Key
|
||||
rand *rand.Rand
|
||||
master string
|
||||
updateMode string
|
||||
transferMode string
|
||||
nameservers []*models.Nameserver
|
||||
transferKey *Key
|
||||
updateKey *Key
|
||||
hasDnssecRecords bool
|
||||
serverHasBuggyCNAME bool
|
||||
}
|
||||
|
||||
func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
@@ -132,6 +135,12 @@ func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (provi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(config["buggy-cname"])) {
|
||||
case "yes", "true":
|
||||
api.serverHasBuggyCNAME = true
|
||||
default:
|
||||
api.serverHasBuggyCNAME = false
|
||||
}
|
||||
for key := range config {
|
||||
switch key {
|
||||
case "master",
|
||||
@@ -139,7 +148,9 @@ func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (provi
|
||||
"update-key",
|
||||
"transfer-key",
|
||||
"update-mode",
|
||||
"transfer-mode":
|
||||
"transfer-mode",
|
||||
"domain",
|
||||
"TYPE":
|
||||
continue
|
||||
default:
|
||||
printer.Printf("[Warning] AXFRDDNS: unknown key in `creds.json` (%s)\n", key)
|
||||
@@ -301,7 +312,7 @@ func (c *axfrddnsProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
|
||||
if len(foundRecords) >= 1 && foundRecords[len(foundRecords)-1].Type == "SOA" {
|
||||
// The SOA is sent two times: as the first and the last record
|
||||
// See section 2.2 of RFC5936
|
||||
// See section 2.2 of RFC5936. We remove the later one.
|
||||
foundRecords = foundRecords[:len(foundRecords)-1]
|
||||
}
|
||||
|
||||
@@ -309,153 +320,309 @@ func (c *axfrddnsProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
foundRecords = append(foundRecords, foundDNSSecRecords)
|
||||
}
|
||||
|
||||
return foundRecords, nil
|
||||
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *axfrddnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
|
||||
foundRecords, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" {
|
||||
// Ignoring the SOA, others providers don't manage it either.
|
||||
foundRecords = foundRecords[1:]
|
||||
}
|
||||
|
||||
hasDnssecRecords := false
|
||||
c.hasDnssecRecords = false
|
||||
if len(foundRecords) >= 1 {
|
||||
last := foundRecords[len(foundRecords)-1]
|
||||
if last.Type == "TXT" &&
|
||||
last.Name == dnssecDummyLabel &&
|
||||
len(last.TxtStrings) == 1 &&
|
||||
last.TxtStrings[0] == dnssecDummyTxt {
|
||||
hasDnssecRecords = true
|
||||
c.hasDnssecRecords = true
|
||||
foundRecords = foundRecords[0:(len(foundRecords) - 1)]
|
||||
}
|
||||
}
|
||||
|
||||
return foundRecords, nil
|
||||
|
||||
}
|
||||
|
||||
// BuildCorrection return a Correction for a given set of DDNS update and the corresponding message.
|
||||
func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []string, update *dns.Msg) *models.Correction {
|
||||
return &models.Correction{
|
||||
Msg: fmt.Sprintf("DDNS UPDATES to '%s' (primary master: '%s'). Changes:\n%s", dc.Name, c.master, strings.Join(msgs, "\n")),
|
||||
F: func() error {
|
||||
|
||||
client := new(dns.Client)
|
||||
client.Net = c.updateMode
|
||||
client.Timeout = dnsTimeout
|
||||
if c.updateKey != nil {
|
||||
client.TsigSecret =
|
||||
map[string]string{c.updateKey.id: c.updateKey.secret}
|
||||
update.SetTsig(c.updateKey.id, c.updateKey.algo, 300, time.Now().Unix())
|
||||
if c.updateKey.algo == dns.HmacMD5 {
|
||||
client.TsigProvider = md5Provider(c.updateKey.secret)
|
||||
}
|
||||
}
|
||||
|
||||
msg, _, err := client.Exchange(update, c.master)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.MsgHdr.Rcode != 0 {
|
||||
return fmt.Errorf("[Error] AXFRDDNS: nameserver refused to update the zone: %s (%d)",
|
||||
dns.RcodeToString[msg.MsgHdr.Rcode],
|
||||
msg.MsgHdr.Rcode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// hasDeletionForName returns true if there exist a corrections for [name] which is a deletion
|
||||
func hasDeletionForName(changes diff2.ChangeList, name string) bool {
|
||||
for _, change := range changes {
|
||||
switch change.Type {
|
||||
case diff2.DELETE:
|
||||
if change.Old[0].Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasNSDeletion returns true if there exist a correction that deletes or changes an NS record
|
||||
func hasNSDeletion(changes diff2.ChangeList) bool {
|
||||
for _, change := range changes {
|
||||
switch change.Type {
|
||||
case diff2.CHANGE:
|
||||
if change.Old[0].Type == "NS" && change.Old[0].Name == "@" {
|
||||
return true
|
||||
}
|
||||
case diff2.DELETE:
|
||||
if change.Old[0].Type == "NS" && change.Old[0].Name == "@" {
|
||||
return true
|
||||
}
|
||||
case diff2.CREATE:
|
||||
case diff2.REPORT:
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(foundRecords) // Autosplit long TXT records
|
||||
|
||||
// Ignoring the SOA, others providers don't manage it either.
|
||||
if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" {
|
||||
foundRecords = foundRecords[1:]
|
||||
}
|
||||
|
||||
// TODO(tlim): This check should be done on all providers. Move to the global validation code.
|
||||
if dc.AutoDNSSEC == "on" && !hasDnssecRecords {
|
||||
if dc.AutoDNSSEC == "on" && !c.hasDnssecRecords {
|
||||
printer.Printf("Warning: AUTODNSSEC is enabled, but no DNSKEY or RRSIG record was found in the AXFR answer!\n")
|
||||
}
|
||||
if dc.AutoDNSSEC == "off" && hasDnssecRecords {
|
||||
if dc.AutoDNSSEC == "off" && c.hasDnssecRecords {
|
||||
printer.Printf("Warning: AUTODNSSEC is disabled, but DNSKEY or RRSIG records were found in the AXFR answer!\n")
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
// An RFC2136-compliant server must silently ignore an
|
||||
// update that inserts a non-CNAME RRset when a CNAME RR
|
||||
// with the same name is present in the zone (and
|
||||
// vice-versa). Therefore we prefer to first remove records
|
||||
// and then insert new ones.
|
||||
//
|
||||
// Compliant servers must also silently ignore an update
|
||||
// that removes the last NS record of a zone. Therefore we
|
||||
// don't want to remove all NS records before inserting a
|
||||
// new one. Then, when an update want to change a NS record,
|
||||
// we first insert a dummy NS record that we will remove
|
||||
// at the end of the batched update.
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, mod diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
var msgs []string
|
||||
var msgs2 []string
|
||||
update := new(dns.Msg)
|
||||
update.SetUpdate(dc.Name + ".")
|
||||
update.Id = uint16(c.rand.Intn(math.MaxUint16))
|
||||
update2 := new(dns.Msg)
|
||||
update2.SetUpdate(dc.Name + ".")
|
||||
update2.Id = uint16(c.rand.Intn(math.MaxUint16))
|
||||
hasTwoCorrections := false
|
||||
|
||||
dummyNs1, err := dns.NewRR(dc.Name + ". IN NS 255.255.255.255")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, create, del, mod, err = differ.IncrementalDiff(foundRecords)
|
||||
dummyNs2, err := dns.NewRR(dc.Name + ". IN NS 255.255.255.255")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
// Print a list of changes. Generate an actual change that is the zone
|
||||
changes := false
|
||||
for _, i := range create {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range del {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
for _, i := range mod {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, i)
|
||||
}
|
||||
msg := fmt.Sprintf("DDNS UPDATES to '%s' (primary master: '%s'). Changes:\n%s", dc.Name, c.master, buf)
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
if changes {
|
||||
// Legacy code with the old `diff`
|
||||
|
||||
corrections = append(corrections,
|
||||
&models.Correction{
|
||||
Msg: msg,
|
||||
F: func() error {
|
||||
differ := diff.New(dc)
|
||||
_, create, del, mod, err := differ.IncrementalDiff(foundRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// An RFC2136-compliant server must silently ignore an
|
||||
// update that inserts a non-CNAME RRset when a CNAME RR
|
||||
// with the same name is present in the zone (and
|
||||
// vice-versa). Therefore we prefer to first remove records
|
||||
// and then insert new ones.
|
||||
//
|
||||
// Compliant servers must also silently ignore an update
|
||||
// that removes the last NS record of a zone. Therefore we
|
||||
// don't want to remove all NS records before inserting a
|
||||
// new one. For the particular case of NS record, we prefer
|
||||
// to insert new records before ot remove old ones.
|
||||
//
|
||||
// This remarks does not apply for "modified" NS records, as
|
||||
// updates are processed one-by-one.
|
||||
//
|
||||
// This provider does not allow modifying the TTL of an NS
|
||||
// record in a zone that defines only one NS. That would
|
||||
// would require removing the single NS record, before
|
||||
// adding the new one. But who does that anyway?
|
||||
changes := false
|
||||
buf := &bytes.Buffer{}
|
||||
buf2 := &bytes.Buffer{}
|
||||
|
||||
update := new(dns.Msg)
|
||||
update.SetUpdate(dc.Name + ".")
|
||||
update.Id = uint16(c.rand.Intn(math.MaxUint16))
|
||||
for _, c := range create {
|
||||
if c.Desired.Type == "NS" {
|
||||
update.Insert([]dns.RR{c.Desired.ToRR()})
|
||||
}
|
||||
}
|
||||
for _, c := range del {
|
||||
update.Remove([]dns.RR{c.Existing.ToRR()})
|
||||
}
|
||||
for _, c := range mod {
|
||||
update.Remove([]dns.RR{c.Existing.ToRR()})
|
||||
update.Insert([]dns.RR{c.Desired.ToRR()})
|
||||
}
|
||||
for _, c := range create {
|
||||
if c.Desired.Type != "NS" {
|
||||
update.Insert([]dns.RR{c.Desired.ToRR()})
|
||||
}
|
||||
}
|
||||
// See comment below about hasNSDeletion.
|
||||
hasNSDeletion := false
|
||||
for _, c := range create {
|
||||
if c.Desired.Type == "NS" && c.Desired.Name == "@" {
|
||||
hasNSDeletion = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, c := range del {
|
||||
if c.Existing.Type == "NS" && c.Existing.Name == "@" {
|
||||
hasNSDeletion = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, c := range mod {
|
||||
if c.Existing.Type == "NS" && c.Existing.Name == "@" {
|
||||
hasNSDeletion = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
client := new(dns.Client)
|
||||
client.Net = c.updateMode
|
||||
client.Timeout = dnsTimeout
|
||||
if c.updateKey != nil {
|
||||
client.TsigSecret =
|
||||
map[string]string{c.updateKey.id: c.updateKey.secret}
|
||||
update.SetTsig(c.updateKey.id, c.updateKey.algo, 300, time.Now().Unix())
|
||||
if c.updateKey.algo == dns.HmacMD5 {
|
||||
client.TsigProvider = md5Provider(c.updateKey.secret)
|
||||
}
|
||||
}
|
||||
if hasNSDeletion {
|
||||
update.Insert([]dns.RR{dummyNs1})
|
||||
}
|
||||
|
||||
msg, _, err := client.Exchange(update, c.master)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.MsgHdr.Rcode != 0 {
|
||||
return fmt.Errorf("[Error] AXFRDDNS: nameserver refused to update the zone: %s (%d)",
|
||||
dns.RcodeToString[msg.MsgHdr.Rcode],
|
||||
msg.MsgHdr.Rcode)
|
||||
for _, change := range del {
|
||||
changes = true
|
||||
fmt.Fprintln(buf, change)
|
||||
update.Remove([]dns.RR{change.Existing.ToRR()})
|
||||
}
|
||||
for _, change := range mod {
|
||||
changes = true
|
||||
if c.serverHasBuggyCNAME && change.Desired.Type == "CNAME" {
|
||||
fmt.Fprintln(buf, change.String()+color.RedString(" (delete)"))
|
||||
update.Remove([]dns.RR{change.Existing.ToRR()})
|
||||
hasTwoCorrections = true
|
||||
fmt.Fprintln(buf2, change.String()+color.GreenString(" (create)"))
|
||||
update2.Insert([]dns.RR{change.Desired.ToRR()})
|
||||
} else {
|
||||
fmt.Fprintln(buf, change)
|
||||
update.Remove([]dns.RR{change.Existing.ToRR()})
|
||||
update.Insert([]dns.RR{change.Desired.ToRR()})
|
||||
}
|
||||
}
|
||||
for _, change := range create {
|
||||
changes = true
|
||||
splitted := false
|
||||
if c.serverHasBuggyCNAME && change.Desired.Type == "CNAME" {
|
||||
for _, change2 := range del {
|
||||
if change2.Existing.Name == change.Desired.Name {
|
||||
splitted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if splitted {
|
||||
hasTwoCorrections = true
|
||||
fmt.Fprintln(buf2, change)
|
||||
update2.Insert([]dns.RR{change.Desired.ToRR()})
|
||||
} else {
|
||||
fmt.Fprintln(buf, change)
|
||||
update.Insert([]dns.RR{change.Desired.ToRR()})
|
||||
}
|
||||
}
|
||||
|
||||
if hasNSDeletion {
|
||||
update.Remove([]dns.RR{dummyNs2})
|
||||
}
|
||||
|
||||
if !changes {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if hasTwoCorrections {
|
||||
|
||||
return []*models.Correction{
|
||||
c.BuildCorrection(dc, []string{buf.String()}, update),
|
||||
c.BuildCorrection(dc, []string{buf2.String()}, update2),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
return []*models.Correction{
|
||||
c.BuildCorrection(dc, []string{buf.String()}, update),
|
||||
}, nil
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
changes, err := diff2.ByRecord(foundRecords, dc, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if changes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// A DNS server should silently ignore a DDNS update that removes
|
||||
// the last NS record of a zone. Since modifying a record is
|
||||
// implemented by successively a deletion of the old record and an
|
||||
// insertion of the new one, then modifying all the NS record of a
|
||||
// zone might will fail (even if the the deletion and insertion
|
||||
// are grouped in a single batched update).
|
||||
//
|
||||
// To avoid this case, we will first insert a dummy NS record,
|
||||
// that will be removed at the end of the batched updates. This
|
||||
// record needs to inserted only when all NS records are touched
|
||||
// The current implementation insert this dummy record as soon as
|
||||
// a NS record is deleted or changed.
|
||||
hasNSDeletion := hasNSDeletion(changes)
|
||||
|
||||
if hasNSDeletion {
|
||||
update.Insert([]dns.RR{dummyNs1})
|
||||
}
|
||||
|
||||
for _, change := range changes {
|
||||
switch change.Type {
|
||||
case diff2.DELETE:
|
||||
msgs = append(msgs, change.Msgs[0])
|
||||
update.Remove([]dns.RR{change.Old[0].ToRR()})
|
||||
case diff2.CREATE:
|
||||
if c.serverHasBuggyCNAME &&
|
||||
change.New[0].Type == "CNAME" &&
|
||||
hasDeletionForName(changes, change.New[0].Name) {
|
||||
hasTwoCorrections = true
|
||||
msgs2 = append(msgs2, change.Msgs[0])
|
||||
update2.Insert([]dns.RR{change.New[0].ToRR()})
|
||||
} else {
|
||||
msgs = append(msgs, change.Msgs[0])
|
||||
update.Insert([]dns.RR{change.New[0].ToRR()})
|
||||
}
|
||||
case diff2.CHANGE:
|
||||
if c.serverHasBuggyCNAME && change.New[0].Type == "CNAME" {
|
||||
msgs = append(msgs, change.Msgs[0]+color.RedString(" (delete)"))
|
||||
update.Remove([]dns.RR{change.Old[0].ToRR()})
|
||||
hasTwoCorrections = true
|
||||
msgs2 = append(msgs2, change.Msgs[0]+color.GreenString(" (create)"))
|
||||
update2.Insert([]dns.RR{change.New[0].ToRR()})
|
||||
} else {
|
||||
msgs = append(msgs, change.Msgs[0])
|
||||
update.Remove([]dns.RR{change.Old[0].ToRR()})
|
||||
update.Insert([]dns.RR{change.New[0].ToRR()})
|
||||
}
|
||||
case diff2.REPORT:
|
||||
msgs = append(msgs, change.Msgs...)
|
||||
}
|
||||
}
|
||||
|
||||
if hasNSDeletion {
|
||||
update.Remove([]dns.RR{dummyNs2})
|
||||
}
|
||||
|
||||
if hasTwoCorrections {
|
||||
return []*models.Correction{
|
||||
c.BuildCorrection(dc, msgs, update),
|
||||
c.BuildCorrection(dc, msgs2, update2),
|
||||
}, nil
|
||||
}
|
||||
return []*models.Correction{
|
||||
c.BuildCorrection(dc, msgs, update),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ type azurednsProvider struct {
|
||||
zones map[string]*adns.Zone
|
||||
resourceGroup *string
|
||||
subscriptionID *string
|
||||
rawRecords map[string][]*adns.RecordSet
|
||||
zoneName map[string]string
|
||||
}
|
||||
|
||||
func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
@@ -47,7 +49,14 @@ func newAzureDNS(m map[string]string, metadata json.RawMessage) (*azurednsProvid
|
||||
return nil, recordErr
|
||||
}
|
||||
|
||||
api := &azurednsProvider{zonesClient: zonesClient, recordsClient: recordsClient, resourceGroup: to.StringPtr(rg), subscriptionID: to.StringPtr(subID)}
|
||||
api := &azurednsProvider{
|
||||
zonesClient: zonesClient,
|
||||
recordsClient: recordsClient,
|
||||
resourceGroup: to.StringPtr(rg),
|
||||
subscriptionID: to.StringPtr(subID),
|
||||
rawRecords: map[string][]*adns.RecordSet{},
|
||||
zoneName: map[string]string{},
|
||||
}
|
||||
err := api.getZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -157,6 +166,7 @@ func (a *azurednsProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
@@ -166,40 +176,32 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []
|
||||
return nil, nil, "", errNoExist{domain}
|
||||
}
|
||||
zoneName := *zone.Name
|
||||
records, err := a.fetchRecordSets(zoneName)
|
||||
rawRecords, err := a.fetchRecordSets(zoneName)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
var existingRecords models.Records
|
||||
for _, set := range records {
|
||||
for _, set := range rawRecords {
|
||||
existingRecords = append(existingRecords, nativeToRecords(set, zoneName)...)
|
||||
}
|
||||
|
||||
// FIXME(tlim): PostProcessRecords is usually called in GetDomainCorrections.
|
||||
models.PostProcessRecords(existingRecords)
|
||||
a.rawRecords[domain] = rawRecords
|
||||
a.zoneName[domain] = zoneName
|
||||
|
||||
// FIXME(tlim): The "records" return value is usually stored in RecordConfig.Original.
|
||||
return existingRecords, records, zoneName, nil
|
||||
return existingRecords, rawRecords, zoneName, nil
|
||||
}
|
||||
|
||||
func (a *azurednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRecords, records, zoneName, err := a.getExistingRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
records := a.rawRecords[dc.Name]
|
||||
zoneName := a.zoneName[dc.Name]
|
||||
|
||||
differ := diff.New(dc)
|
||||
namesToUpdate, err := differ.ChangedGroups(existingRecords)
|
||||
if err != nil {
|
||||
@@ -309,13 +311,6 @@ func (a *azurednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
F: func() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second)
|
||||
defer cancel()
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: 3 a.recordsClient.CreateOrUpdate(ctx, %v, %v, %v, %v, %+v, nil)\n", *a.resourceGroup, zoneName, recordName, recordType, *rrset)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: 3 rrset: %+v\n", *rrset)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: 3 properties: %+v\n", rrset.Properties)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: 3 TargetResource: %+v\n", rrset.Properties.TargetResource)
|
||||
// if rrset.Properties.TargetResource != nil {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: 3 TargetResourceID: %+v\n", *rrset.Properties.TargetResource.ID)
|
||||
// }
|
||||
_, err := a.recordsClient.CreateOrUpdate(ctx, *a.resourceGroup, zoneName, recordName, recordType, *rrset, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -347,14 +342,8 @@ func (a *azurednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// for i, j := range changes {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: CHANGE[%v] = %+v\n", i, j)
|
||||
// }
|
||||
|
||||
for _, change := range changes {
|
||||
|
||||
//fmt.Fprintf(os.Stderr, "\n\nCHANGE=%v\n", change)
|
||||
|
||||
// Copy all param values to local variables to avoid overwrites
|
||||
msgs := change.MsgsJoined
|
||||
dcn := dc.Name
|
||||
@@ -364,34 +353,14 @@ func (a *azurednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
case diff2.REPORT:
|
||||
corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined})
|
||||
case diff2.CHANGE, diff2.CREATE:
|
||||
|
||||
changeNew := change.New
|
||||
|
||||
// for i, j := range change.Old {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: OLD[%d] = %+v ttl=%d\n", i, j, j.TTL)
|
||||
// }
|
||||
// for i, j := range change.New {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: NEW[%d] = %+v ttl=%d\n", i, j, j.TTL)
|
||||
// }
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: CHANGE = \n%v\n", change)
|
||||
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: msgs,
|
||||
F: func() error {
|
||||
return a.recordCreate(dcn, chaKey, changeNew)
|
||||
},
|
||||
})
|
||||
|
||||
case diff2.DELETE:
|
||||
|
||||
// for i, j := range change.Old {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: OLD[%d] = %+v\n", i, j)
|
||||
// }
|
||||
// for i, j := range change.New {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: NEW[%d] = %+v\n", i, j)
|
||||
// }
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: CHANGE = \n%v\n", change)
|
||||
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: msgs,
|
||||
F: func() error {
|
||||
@@ -414,31 +383,16 @@ func (a *azurednsProvider) recordCreate(zoneName string, reckey models.RecordKey
|
||||
return err
|
||||
}
|
||||
|
||||
// rrset, _, err := a.recordToNativeDiff2(reckey, recs)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
var recordName string
|
||||
var i int64
|
||||
for _, r := range recs {
|
||||
i = int64(r.TTL)
|
||||
recordName = r.Name
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: rn=%v ttl=%d\n", recordName, i)
|
||||
}
|
||||
rrset.Properties.TTL = &i
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second)
|
||||
defer cancel()
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: a.recordsClient.CreateOrUpdate(%v, %v, %v, %v, %+v)\n", *a.resourceGroup, zoneName, recordName, azRecType, *rrset)
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: rrset.Properties=%+v\n", *rrset.Properties)
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: recordCreate a.recordsClient.CreateOrUpdate(ctx, %v, %v, %v, %v, %+v, nil)\n", *a.resourceGroup, zoneName, recordName, azRecType, *rrset)
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: recordCreate rrset: %+v\n", *rrset)
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: recordCreate properties: %+v\n", rrset.Properties)
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: recordCreate TargetResource: %+v\n", rrset.Properties.TargetResource)
|
||||
// if rrset.Properties.TargetResource != nil {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: recordCreate TargetResourceID: %+v\n", *rrset.Properties.TargetResource.ID)
|
||||
// }
|
||||
_, err = a.recordsClient.CreateOrUpdate(ctx, *a.resourceGroup, zoneName, recordName, azRecType, *rrset, nil)
|
||||
return err
|
||||
}
|
||||
@@ -446,12 +400,10 @@ func (a *azurednsProvider) recordCreate(zoneName string, reckey models.RecordKey
|
||||
func (a *azurednsProvider) recordDelete(zoneName string, reckey models.RecordKey, recs models.Records) error {
|
||||
|
||||
shortName := strings.TrimSuffix(reckey.NameFQDN, "."+zoneName)
|
||||
//_, azRecType, err := a.recordToNative(reckey, recs)
|
||||
if shortName == zoneName {
|
||||
shortName = "@"
|
||||
}
|
||||
|
||||
//azRecType, err := nativeToRecordType(to.StringPtr(*recordSet.Type))
|
||||
azRecType, err := nativeToRecordTypeDiff2(to.StringPtr(reckey.Type))
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -459,7 +411,6 @@ func (a *azurednsProvider) recordDelete(zoneName string, reckey models.RecordKey
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second)
|
||||
defer cancel()
|
||||
//fmt.Fprintf(os.Stderr, "DEBUG: a.recordsClient.Delete(%v, %v, %v, %v)\n", *a.resourceGroup, zoneName, shortName, azRecType)
|
||||
_, err = a.recordsClient.Delete(ctx, *a.resourceGroup, zoneName, shortName, azRecType, nil)
|
||||
return err
|
||||
}
|
||||
@@ -524,7 +475,6 @@ func nativeToRecordTypeDiff2(recordType *string) (adns.RecordType, error) {
|
||||
|
||||
func safeTarget(t *string) string {
|
||||
if t == nil {
|
||||
//panic("no TARGET")
|
||||
return "foundnil"
|
||||
}
|
||||
return *t
|
||||
@@ -802,34 +752,11 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor
|
||||
}
|
||||
recordSet.Properties.CaaRecords = append(recordSet.Properties.CaaRecords, &adns.CaaRecord{Value: to.StringPtr(rec.GetTargetField()), Tag: to.StringPtr(rec.CaaTag), Flags: to.Int32Ptr(int32(rec.CaaFlag))})
|
||||
case "AZURE_ALIAS_A", "AZURE_ALIAS_AAAA", "AZURE_ALIAS_CNAME":
|
||||
//case "AZURE_ALIAS":
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS recordToNativeDiff2 rec=%+v\n", rec)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rec.Type=%v\n", rec.Type)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rec.TTL=%v\n", rec.TTL)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rec.Label=%v\n", rec.GetLabel())
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rec.Target=%v\n", rec.GetTargetField())
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rec.AzureAlias=%v\n", rec.AzureAlias)
|
||||
|
||||
// OLD *recordSet.Type = rec.AzureAlias["type"]
|
||||
// NEW:
|
||||
aatype := rec.AzureAlias["type"]
|
||||
recordSet.Type = &aatype
|
||||
// if aatype == "CNAME" {
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS Cname -> MS.n.dnszones.CNAME\n")
|
||||
// aatype = "Microsoft.Network/dnszones/CNAME"
|
||||
// recordSet.Properties.CnameRecord = adns.CnameRecord{Cname: to.StringPtr(rec.GetTargetField())}
|
||||
// // recordSet.Properties.CnameRecord.Cname
|
||||
// //recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: to.StringPtr(rec.GetTargetField())}
|
||||
// }
|
||||
|
||||
// OLD: recordSet.Properties.TargetResource = &adns.SubResource{ID: to.StringPtr(rec.GetTargetField())}
|
||||
// NEW:
|
||||
aatarg := to.StringPtr(rec.GetTargetField())
|
||||
aasub := adns.SubResource{ID: aatarg}
|
||||
recordSet.Properties.TargetResource = &aasub
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rrset.Type=%v\n", *recordSet.Type)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rrset.Target=%v\n", *aatarg)
|
||||
// fmt.Fprintf(os.Stderr, "DEBUG: AZURE_ALIAS rrset.TargetRes=%+v\n", aasub)
|
||||
|
||||
default:
|
||||
return nil, adns.RecordTypeA, fmt.Errorf("recordToNativeDiff2 RTYPE %v UNIMPLEMENTED", recordKeyType) // ands.A is a placeholder
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/prettyzone"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -202,29 +201,11 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
|
||||
return foundRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *bindProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
comments := make([]string, 0, 5)
|
||||
comments = append(comments,
|
||||
fmt.Sprintf("generated with dnscontrol %s", time.Now().Format(time.RFC3339)),
|
||||
)
|
||||
if dc.AutoDNSSEC == "on" {
|
||||
// This does nothing but reminds the user to add the correct
|
||||
// auto-dnssecc zone statement to named.conf.
|
||||
// While it is a no-op, it is useful for situations where a zone
|
||||
// has multiple providers.
|
||||
comments = append(comments, "Automatic DNSSEC signing requested")
|
||||
}
|
||||
|
||||
c.zonefile = filepath.Join(c.directory,
|
||||
makeFileName(c.filenameformat, dc.UniqueName, dc.Name, dc.Tag))
|
||||
|
||||
foundRecords, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := false
|
||||
var msg string
|
||||
|
||||
// Find the SOA records; use them to make or update the desired SOA.
|
||||
var foundSoa *models.RecordConfig
|
||||
@@ -250,13 +231,6 @@ func (c *bindProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.
|
||||
c.skipNextSoaIncrease = true
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
changes := false
|
||||
var msg string
|
||||
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
differ := diff.New(dc)
|
||||
@@ -296,6 +270,7 @@ func (c *bindProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.
|
||||
} else {
|
||||
|
||||
var msgs []string
|
||||
var err error
|
||||
msgs, changes, err = diff2.ByZone(foundRecords, dc, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -309,6 +284,18 @@ func (c *bindProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.
|
||||
//fmt.Printf("DEBUG: BIND changes=%v\n", changes)
|
||||
if changes {
|
||||
|
||||
comments := make([]string, 0, 5)
|
||||
comments = append(comments,
|
||||
fmt.Sprintf("generated with dnscontrol %s", time.Now().Format(time.RFC3339)),
|
||||
)
|
||||
if dc.AutoDNSSEC == "on" {
|
||||
// This does nothing but reminds the user to add the correct
|
||||
// auto-dnssecc zone statement to named.conf.
|
||||
// While it is a no-op, it is useful for situations where a zone
|
||||
// has multiple providers.
|
||||
comments = append(comments, "Automatic DNSSEC signing requested")
|
||||
}
|
||||
|
||||
// We only change the serial number if there is a change.
|
||||
if !c.skipNextSoaIncrease {
|
||||
desiredSoa.SoaSerial = nextSerial
|
||||
|
||||
@@ -3,7 +3,6 @@ package cloudflare
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
@@ -15,7 +14,6 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
"github.com/cloudflare/cloudflare-go"
|
||||
"github.com/fatih/color"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -112,17 +110,19 @@ 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) {
|
||||
id, err := c.getDomainID(domain)
|
||||
|
||||
domainID, err := c.getDomainID(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records, err := c.getRecordsForDomain(id, domain)
|
||||
records, err := c.getRecordsForDomain(domainID, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, rec := range records {
|
||||
if rec.TTL == 1 {
|
||||
rec.TTL = 0
|
||||
if rec.TTL == 0 {
|
||||
rec.TTL = 1
|
||||
}
|
||||
// Store the proxy status ("orange cloud") for use by get-zones:
|
||||
m := getProxyMetadata(rec)
|
||||
@@ -133,6 +133,37 @@ func (c *cloudflareProvider) GetZoneRecords(domain string) (models.Records, erro
|
||||
rec.Metadata["cloudflare_proxy"] = p
|
||||
}
|
||||
}
|
||||
|
||||
// // FIXME(tlim) Why is this needed???
|
||||
// // I don't know. Let's comment it out and see if anything breaks.
|
||||
// for i := len(records) - 1; i >= 0; i-- {
|
||||
// rec := records[i]
|
||||
// // Delete ignore labels
|
||||
// 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:]...)
|
||||
// }
|
||||
// }
|
||||
|
||||
if c.manageRedirects {
|
||||
prs, err := c.getPageRules(domainID, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records = append(records, prs...)
|
||||
}
|
||||
|
||||
if c.manageWorkers {
|
||||
wrs, err := c.getWorkerRoutes(domainID, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records = append(records, wrs...)
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(records)
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
@@ -149,52 +180,26 @@ func (c *cloudflareProvider) getDomainID(name string) (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainID, err := c.getDomainID(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records, err := c.getRecordsForDomain(domainID, dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
|
||||
if err := c.preprocessConfig(dc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := len(records) - 1; i >= 0; i-- {
|
||||
rec := records[i]
|
||||
// Delete ignore labels
|
||||
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:]...)
|
||||
}
|
||||
}
|
||||
// for i := len(records) - 1; i >= 0; i-- {
|
||||
// rec := records[i]
|
||||
// // Delete ignore labels
|
||||
// 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:]...)
|
||||
// }
|
||||
// }
|
||||
|
||||
if c.manageRedirects {
|
||||
prs, err := c.getPageRules(domainID, dc.Name)
|
||||
//printer.Printf("GET PAGE RULES:\n")
|
||||
//for i, p := range prs {
|
||||
// printer.Printf("%03d: %q\n", i, p.GetTargetField())
|
||||
//}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records = append(records, prs...)
|
||||
}
|
||||
checkNSModifications(dc)
|
||||
|
||||
if c.manageWorkers {
|
||||
wrs, err := c.getWorkerRoutes(domainID, dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records = append(records, wrs...)
|
||||
domainID, err := c.getDomainID(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, rec := range dc.Records {
|
||||
@@ -207,24 +212,13 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
if rec.Metadata[metaProxy] != "off" {
|
||||
rec.TTL = 1
|
||||
}
|
||||
if labelMatches(rec.GetLabel(), c.ignoredLabels) {
|
||||
log.Fatalf("FATAL: dnsconfig contains label that matches ignored_labels: %#v is in %v)\n", rec.GetLabel(), c.ignoredLabels)
|
||||
}
|
||||
// if labelMatches(rec.GetLabel(), c.ignoredLabels) {
|
||||
// log.Fatalf("FATAL: dnsconfig contains label that matches ignored_labels: %#v is in %v)\n", rec.GetLabel(), c.ignoredLabels)
|
||||
// }
|
||||
}
|
||||
|
||||
checkNSModifications(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(records)
|
||||
//txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
// Don't split.
|
||||
// Cloudflare's API only supports one TXT string of any non-zero length. No
|
||||
// multiple strings.
|
||||
// When serving the DNS record, it splits strings >255 octets into
|
||||
// individual segments of 255 each. However that is hidden from the API.
|
||||
// Therefore, whether the string is 1 octet or thousands, just store it as
|
||||
// one string in the first element of .TxtStrings.
|
||||
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
@@ -347,7 +341,7 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
corrs = c.mkCreateCorrection(createRec, domainID, msg)
|
||||
// DS records must always have a corresponding NS record.
|
||||
// Therefore, we create NS records before any DS records.
|
||||
addToFront = createRec.Type == "NS"
|
||||
addToFront = (createRec.Type == "NS")
|
||||
case diff2.CHANGE:
|
||||
newrec := inst.New[0]
|
||||
oldrec := inst.Old[0]
|
||||
@@ -359,7 +353,7 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
corrs = c.mkDeleteCorrection(deleteRecType, deleteRecOrig, domainID, msg)
|
||||
// DS records must always have a corresponding NS record.
|
||||
// Therefore, we remove DS records before any NS records.
|
||||
addToFront = deleteRecType == "DS"
|
||||
addToFront = (deleteRecType == "DS")
|
||||
}
|
||||
|
||||
if addToFront {
|
||||
@@ -387,13 +381,16 @@ func (c *cloudflareProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
}
|
||||
|
||||
func genComparable(rec *models.RecordConfig) string {
|
||||
//fmt.Printf("DEBUG: genComparable called %v:%v meta=%+v\n", rec.Type, rec.GetLabel(), rec.Metadata)
|
||||
if rec.Type == "A" || rec.Type == "AAAA" || rec.Type == "CNAME" {
|
||||
proxy := rec.Metadata[metaProxy]
|
||||
if proxy != "" {
|
||||
//return "proxy=" + rec.Metadata[metaProxy]
|
||||
if proxy == "on" {
|
||||
proxy = "true"
|
||||
}
|
||||
if proxy == "off" {
|
||||
proxy = "false"
|
||||
}
|
||||
return "proxy=" + proxy
|
||||
//return fmt.Sprintf("proxy:%v=%s", rec.Type, proxy)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
@@ -417,6 +414,7 @@ func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, dom
|
||||
}
|
||||
|
||||
func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordConfig, domainID string, msg string) []*models.Correction {
|
||||
|
||||
var idTxt string
|
||||
switch oldrec.Type {
|
||||
case "PAGE_RULE":
|
||||
@@ -433,14 +431,14 @@ func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordCon
|
||||
return []*models.Correction{{
|
||||
Msg: msg,
|
||||
F: func() error {
|
||||
return c.updatePageRule(oldrec.Original.(cloudflare.PageRule).ID, domainID, newrec.GetTargetField())
|
||||
return c.updatePageRule(idTxt, domainID, newrec.GetTargetField())
|
||||
},
|
||||
}}
|
||||
case "WORKER_ROUTE":
|
||||
return []*models.Correction{{
|
||||
Msg: msg,
|
||||
F: func() error {
|
||||
return c.updateWorkerRoute(oldrec.Original.(cloudflare.WorkerRoute).ID, domainID, newrec.GetTargetField())
|
||||
return c.updateWorkerRoute(idTxt, domainID, newrec.GetTargetField())
|
||||
},
|
||||
}}
|
||||
default:
|
||||
|
||||
@@ -109,6 +109,9 @@ func (c *cloudnsProvider) fetchAvailableTTLValues(domain string) error {
|
||||
}
|
||||
|
||||
func (c *cloudnsProvider) fetchDomainList() error {
|
||||
// FIXME(tlim): This should return nil if c.domainIndex != nil. Then all
|
||||
// the callers won't have to check if c.domainIndex == nil before calling.
|
||||
|
||||
c.domainIndex = map[string]string{}
|
||||
rowsPerPage := 100
|
||||
page := 1
|
||||
|
||||
@@ -71,14 +71,45 @@ func (c *cloudnsProvider) GetNameservers(domain string) ([]*models.Nameserver, e
|
||||
return models.ToNameservers(c.nameserversNames)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (c *cloudnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// // GetDomainCorrections returns the corrections for a domain.
|
||||
// func (c *cloudnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// dc, err := dc.Copy()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
dc.Punycode()
|
||||
// dc.Punycode()
|
||||
|
||||
// if c.domainIndex == nil {
|
||||
// if err := c.fetchDomainList(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
// _, ok := c.domainIndex[dc.Name]
|
||||
// if !ok {
|
||||
// return nil, fmt.Errorf("'%s' not a zone in ClouDNS account", dc.Name)
|
||||
// }
|
||||
|
||||
// existingRecords, err := c.GetZoneRecords(dc.Name)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// // Normalize
|
||||
// models.PostProcessRecords(existingRecords)
|
||||
|
||||
// // Get a list of available TTL values.
|
||||
// // The TTL list needs to be obtained for each domain, so get it first here.
|
||||
// c.fetchAvailableTTLValues(dc.Name)
|
||||
// // ClouDNS can only be specified from a specific TTL list, so change the TTL in advance.
|
||||
// for _, record := range dc.Records {
|
||||
// record.TTL = fixTTL(record.TTL)
|
||||
// }
|
||||
|
||||
// return c.GetZoneRecordsCorrections(dc, existingRecords)
|
||||
// }
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *cloudnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
if c.domainIndex == nil {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
@@ -90,13 +121,6 @@ func (c *cloudnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
||||
return nil, fmt.Errorf("'%s' not a zone in ClouDNS account", dc.Name)
|
||||
}
|
||||
|
||||
existingRecords, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
// Get a list of available TTL values.
|
||||
// The TTL list needs to be obtained for each domain, so get it first here.
|
||||
c.fetchAvailableTTLValues(dc.Name)
|
||||
|
||||
@@ -75,46 +75,8 @@ func (client *providerClient) GetNameservers(domain string) ([]*models.Nameserve
|
||||
return models.ToNameservers(nss)
|
||||
}
|
||||
|
||||
// GetDomainCorrections get the current and existing records,
|
||||
// post-process them, and generate corrections.
|
||||
// NB(tlim): This function should be exactly the same in all DNS providers. Once
|
||||
// all providers do this, we can eliminate it and use a Go interface instead.
|
||||
func (client *providerClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
existing, err := client.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
//txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
clean := PrepFoundRecords(existing)
|
||||
PrepDesiredRecords(dc)
|
||||
return client.GenerateDomainCorrections(dc, clean)
|
||||
}
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
// Sort through the dc.Records, eliminate any that can't be
|
||||
// supported; modify any that need adjustments to work with the
|
||||
// provider. We try to do minimal changes otherwise it gets
|
||||
// confusing.
|
||||
|
||||
dc.Punycode()
|
||||
}
|
||||
|
||||
// GetDomainCorrections gets existing records, diffs them against existing, and returns corrections.
|
||||
func (client *providerClient) GenerateDomainCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (client *providerClient) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
//txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
|
||||
@@ -74,28 +74,28 @@ func (c *desecProvider) GetNameservers(domain string) ([]*models.Nameserver, err
|
||||
return models.ToNameservers(defaultNameServerNames)
|
||||
}
|
||||
|
||||
func (c *desecProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
if dc.AutoDNSSEC == "off" {
|
||||
printer.Printf("Notice: DNSSEC signing was not requested, but cannot be turned off. (deSEC always signs all records.)\n")
|
||||
}
|
||||
// func (c *desecProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// if dc.AutoDNSSEC == "off" {
|
||||
// printer.Printf("Notice: DNSSEC signing was not requested, but cannot be turned off. (deSEC always signs all records.)\n")
|
||||
// }
|
||||
|
||||
existing, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
clean := PrepFoundRecords(existing)
|
||||
var minTTL uint32
|
||||
c.mutex.Lock()
|
||||
if ttl, ok := c.domainIndex[dc.Name]; !ok {
|
||||
minTTL = 3600
|
||||
} else {
|
||||
minTTL = ttl
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
PrepDesiredRecords(dc, minTTL)
|
||||
return c.GenerateDomainCorrections(dc, clean)
|
||||
}
|
||||
// existing, err := c.GetZoneRecords(dc.Name)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// models.PostProcessRecords(existing)
|
||||
// clean := PrepFoundRecords(existing)
|
||||
// var minTTL uint32
|
||||
// c.mutex.Lock()
|
||||
// if ttl, ok := c.domainIndex[dc.Name]; !ok {
|
||||
// minTTL = 3600
|
||||
// } else {
|
||||
// minTTL = ttl
|
||||
// }
|
||||
// c.mutex.Unlock()
|
||||
// PrepDesiredRecords(dc, minTTL)
|
||||
// return c.GetZoneRecordsCorrections(dc, clean)
|
||||
// }
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (c *desecProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
@@ -110,6 +110,7 @@ func (c *desecProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
for _, rr := range records {
|
||||
existingRecords = append(existingRecords, nativeToRecords(rr, domain)...)
|
||||
}
|
||||
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
@@ -123,14 +124,6 @@ func (c *desecProvider) EnsureZoneExists(domain string) error {
|
||||
return c.createDomain(domain)
|
||||
}
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) {
|
||||
// Sort through the dc.Records, eliminate any that can't be
|
||||
@@ -138,8 +131,7 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) {
|
||||
// provider. We try to do minimal changes otherwise it gets
|
||||
// confusing.
|
||||
|
||||
dc.Punycode()
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
//dc.Punycode()
|
||||
recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" {
|
||||
@@ -158,12 +150,19 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) {
|
||||
dc.Records = recordsToKeep
|
||||
}
|
||||
|
||||
// GenerateDomainCorrections takes the desired and existing records
|
||||
// and produces a Correction list. The correction list is simply
|
||||
// a list of functions to call to actually make the desired
|
||||
// correction, and a message to output to the user when the change is
|
||||
// made.
|
||||
func (c *desecProvider) GenerateDomainCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
|
||||
var minTTL uint32
|
||||
c.mutex.Lock()
|
||||
if ttl, ok := c.domainIndex[dc.Name]; !ok {
|
||||
minTTL = 3600
|
||||
} else {
|
||||
minTTL = ttl
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
PrepDesiredRecords(dc, minTTL)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var err error
|
||||
|
||||
@@ -133,20 +133,12 @@ func (api *digitaloceanProvider) GetZoneRecords(domain string) (models.Records,
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corretions for the domain.
|
||||
func (api *digitaloceanProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
ctx := context.Background()
|
||||
dc.Punycode()
|
||||
|
||||
existingRecords, err := api.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var corrections []*models.Correction
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
@@ -133,17 +133,16 @@ func (c *dnsimpleProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
cleanedRecords = append(cleanedRecords, rec)
|
||||
}
|
||||
|
||||
// Apex NS are immutable via API
|
||||
cleanedRecords = removeApexNS(cleanedRecords)
|
||||
|
||||
return cleanedRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns corrections that update a domain.
|
||||
func (c *dnsimpleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
func (c *dnsimpleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
var corrections []*models.Correction
|
||||
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
removeOtherApexNS(dc)
|
||||
|
||||
dnssecFixes, err := c.getDNSSECCorrections(dc)
|
||||
if err != nil {
|
||||
@@ -151,25 +150,13 @@ func (c *dnsimpleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
}
|
||||
corrections = append(corrections, dnssecFixes...)
|
||||
|
||||
records, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Apex NS are immutable via API
|
||||
actual := removeApexNS(records)
|
||||
removeOtherApexNS(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(actual)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(actual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -63,14 +63,47 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro
|
||||
return api, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *dnsMadeEasyProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// // GetDomainCorrections returns the corrections for a domain.
|
||||
// func (api *dnsMadeEasyProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// dc, err := dc.Copy()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
err = dc.Punycode()
|
||||
// err = dc.Punycode()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// for _, rec := range dc.Records {
|
||||
// if rec.Type == "ALIAS" {
|
||||
// // ALIAS is called ANAME on DNS Made Easy
|
||||
// rec.Type = "ANAME"
|
||||
// } else if rec.Type == "NS" {
|
||||
// // NS records have fixed TTL on DNS Made Easy and it cannot be changed
|
||||
// rec.TTL = fixedNameServerRecordTTL
|
||||
// }
|
||||
// }
|
||||
|
||||
// domainName := dc.Name
|
||||
|
||||
// // Get existing records
|
||||
// existingRecords, err := api.GetZoneRecords(domainName)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// // Normalize
|
||||
// models.PostProcessRecords(existingRecords)
|
||||
|
||||
// return api.GetZoneRecordsCorrections(dc, existingRecords)
|
||||
// }
|
||||
|
||||
func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
domainName := dc.Name
|
||||
domain, err := api.findDomain(domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -85,32 +118,14 @@ func (api *dnsMadeEasyProvider) GetDomainCorrections(dc *models.DomainConfig) ([
|
||||
}
|
||||
}
|
||||
|
||||
domainName := dc.Name
|
||||
|
||||
domain, err := api.findDomain(domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get existing records
|
||||
existingRecords, err := api.GetZoneRecords(domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -25,15 +25,8 @@ func (api *domainNameShopProvider) GetZoneRecords(domain string) (models.Records
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
func (api *domainNameShopProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
existingRecords, err := api.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Merge TXT strings to one string
|
||||
for _, rc := range dc.Records {
|
||||
@@ -48,14 +41,13 @@ func (api *domainNameShopProvider) GetDomainCorrections(dc *models.DomainConfig)
|
||||
}
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, delete, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, delete, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, delete, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -88,22 +88,13 @@ 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(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.
|
||||
}
|
||||
func (c *exoscaleProvider) GetZoneRecords(domainName string) (models.Records, error) {
|
||||
//dc.Punycode()
|
||||
|
||||
// GetDomainCorrections returns a list of corretions for the domain.
|
||||
func (c *exoscaleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
|
||||
domain, err := c.findDomainByName(dc.Name)
|
||||
domain, err := c.findDomainByName(domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainID := *domain.ID
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -165,7 +156,7 @@ func (c *exoscaleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
if record.TTL != nil {
|
||||
rc.TTL = uint32(*record.TTL)
|
||||
}
|
||||
rc.SetLabel(rname, dc.Name)
|
||||
rc.SetLabel(rname, domainName)
|
||||
|
||||
switch rtype {
|
||||
case "ALIAS", "URL":
|
||||
@@ -178,7 +169,7 @@ func (c *exoscaleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
}
|
||||
err = rc.SetTargetMX(prio, rcontent)
|
||||
default:
|
||||
err = rc.PopulateFromString(rtype, rcontent, dc.Name)
|
||||
err = rc.PopulateFromString(rtype, rcontent, domainName)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unparsable record received from exoscale: %w", err)
|
||||
@@ -186,25 +177,33 @@ func (c *exoscaleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
|
||||
existingRecords = append(existingRecords, rc)
|
||||
}
|
||||
removeOtherNS(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *exoscaleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
removeOtherNS(dc)
|
||||
domain, err := c.findDomainByName(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainID := *domain.ID
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, delete, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, delete, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, toDelete, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, del := range delete {
|
||||
for _, del := range toDelete {
|
||||
record := del.Existing.Original.(*egoscale.DNSDomainRecord)
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: del.String(),
|
||||
|
||||
@@ -127,29 +127,6 @@ func newHelper(m map[string]string, metadata json.RawMessage) (*gandiv5Provider,
|
||||
// return zones, nil
|
||||
// }
|
||||
|
||||
// NB(tal): To future-proof your code, all new providers should
|
||||
// implement GetDomainCorrections exactly as you see here
|
||||
// (byte-for-byte the same). In 3.0
|
||||
// we plan on using just the individual calls to GetZoneRecords,
|
||||
// PostProcessRecords, and so on.
|
||||
//
|
||||
// Currently every provider does things differently, which prevents
|
||||
// us from doing things like using GetZoneRecords() of a provider
|
||||
// to make convertzone work with all providers.
|
||||
|
||||
// GetDomainCorrections get the current and existing records,
|
||||
// post-process them, and generate corrections.
|
||||
func (client *gandiv5Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
existing, err := client.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
clean := PrepFoundRecords(existing)
|
||||
PrepDesiredRecords(dc)
|
||||
return client.GenerateDomainCorrections(dc, clean)
|
||||
}
|
||||
|
||||
// GetZoneRecords gathers the DNS records and converts them to
|
||||
// dnscontrol's format.
|
||||
func (client *gandiv5Provider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
@@ -178,14 +155,6 @@ func (client *gandiv5Provider) GetZoneRecords(domain string) (models.Records, er
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
// Sort through the dc.Records, eliminate any that can't be
|
||||
@@ -193,8 +162,6 @@ func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
// provider. We try to do minimal changes otherwise it gets
|
||||
// confusing.
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" && rec.Name != "@" {
|
||||
@@ -224,16 +191,13 @@ func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
dc.Records = recordsToKeep
|
||||
}
|
||||
|
||||
// GenerateDomainCorrections takes the desired and existing records
|
||||
// and produces a Correction list. The correction list is simply
|
||||
// a list of functions to call to actually make the desired
|
||||
// correction, and a message to output to the user when the change is
|
||||
// made.
|
||||
func (client *gandiv5Provider) GenerateDomainCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
if client.debug {
|
||||
debugRecords("GenDC input", existing)
|
||||
}
|
||||
|
||||
PrepDesiredRecords(dc)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
@@ -368,7 +332,7 @@ func (client *gandiv5Provider) GenerateDomainCorrections(dc *models.DomainConfig
|
||||
case diff2.CREATE:
|
||||
// We have to create the label one rtype at a time.
|
||||
// In other words, this is a ByRecordSet API for creation, even though
|
||||
// this is a ByLabel() API for everything else.
|
||||
// this is very ByLabel()-ish for everything else.
|
||||
natives := recordsToNative(inst.New, dc.Name)
|
||||
for _, n := range natives {
|
||||
label := inst.Key.NameFQDN
|
||||
|
||||
@@ -53,6 +53,9 @@ type gcloudProvider struct {
|
||||
project string
|
||||
nameServerSet *string
|
||||
zones map[string]*gdns.ManagedZone
|
||||
// diff1
|
||||
oldRRsMap map[string]map[key]*gdns.ResourceRecordSet
|
||||
zoneNameMap map[string]string
|
||||
}
|
||||
|
||||
type errNoExist struct {
|
||||
@@ -105,6 +108,8 @@ func New(cfg map[string]string, metadata json.RawMessage) (providers.DNSServiceP
|
||||
client: dcli,
|
||||
nameServerSet: nss,
|
||||
project: cfg["project_id"],
|
||||
oldRRsMap: map[string]map[key]*gdns.ResourceRecordSet{},
|
||||
zoneNameMap: map[string]string{},
|
||||
}
|
||||
return g, g.loadZoneInfo()
|
||||
}
|
||||
@@ -168,14 +173,14 @@ 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) {
|
||||
existingRecords, _, _, err := g.getZoneSets(domain)
|
||||
existingRecords, err := g.getZoneSets(domain)
|
||||
return existingRecords, err
|
||||
}
|
||||
|
||||
func (g *gcloudProvider) getZoneSets(domain string) (models.Records, map[key]*gdns.ResourceRecordSet, string, error) {
|
||||
func (g *gcloudProvider) getZoneSets(domain string) (models.Records, error) {
|
||||
rrs, zoneName, err := g.getRecords(domain)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
// convert to dnscontrol RecordConfig format
|
||||
existingRecords := []*models.RecordConfig{}
|
||||
@@ -185,28 +190,33 @@ func (g *gcloudProvider) getZoneSets(domain string) (models.Records, map[key]*gd
|
||||
for _, rec := range set.Rrdatas {
|
||||
rt, err := nativeToRecord(set, rec, domain)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRecords = append(existingRecords, rt)
|
||||
}
|
||||
}
|
||||
return existingRecords, oldRRs, zoneName, err
|
||||
|
||||
g.oldRRsMap[domain] = oldRRs
|
||||
g.zoneNameMap[domain] = zoneName
|
||||
|
||||
return existingRecords, err
|
||||
}
|
||||
|
||||
func (g *gcloudProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
if err := dc.Punycode(); err != nil {
|
||||
return nil, fmt.Errorf("punycode error: %w", err)
|
||||
}
|
||||
existingRecords, oldRRs, zoneName, err := g.getZoneSets(dc.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getzonesets error: %w", err)
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
oldRRs, ok := g.oldRRsMap[dc.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("oldRRsMap: no zone named %q", dc.Name)
|
||||
}
|
||||
zoneName, ok := g.zoneNameMap[dc.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("zoneNameMap: no zone named %q", dc.Name)
|
||||
}
|
||||
|
||||
// first collect keys that have changed
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
@@ -76,17 +76,6 @@ func (c *gcoreProvider) GetNameservers(domain string) ([]*models.Nameserver, err
|
||||
return models.ToNameservers(defaultNameServerNames)
|
||||
}
|
||||
|
||||
func (c *gcoreProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
existing, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
clean := PrepFoundRecords(existing)
|
||||
PrepDesiredRecords(dc)
|
||||
return c.GenerateDomainCorrections(dc, clean)
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (c *gcoreProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
zone, err := c.provider.Zone(c.ctx, domain)
|
||||
@@ -132,19 +121,6 @@ func (c *gcoreProvider) EnsureZoneExists(domain string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
dc.Punycode()
|
||||
}
|
||||
|
||||
func generateChangeMsg(updates []string) string {
|
||||
return strings.Join(updates, "\n")
|
||||
}
|
||||
@@ -154,7 +130,7 @@ func generateChangeMsg(updates []string) string {
|
||||
// a list of functions to call to actually make the desired
|
||||
// correction, and a message to output to the user when the change is
|
||||
// made.
|
||||
func (c *gcoreProvider) GenerateDomainCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
func (c *gcoreProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Make delete happen earlier than creates & updates.
|
||||
var corrections []*models.Correction
|
||||
|
||||
@@ -178,18 +178,8 @@ func (c *hednsProvider) GetNameservers(_ string) ([]*models.Nameserver, error) {
|
||||
return models.ToNameservers(defaultNameservers)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections for the domain.
|
||||
func (c *hednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *hednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Get the SOA record to get the ZoneID, then remove it from the list.
|
||||
zoneID := uint64(0)
|
||||
@@ -203,7 +193,6 @@ func (c *hednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(prunedRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
// Fallback to legacy mode if diff2 is not enabled, remove when diff1 is deprecated.
|
||||
@@ -215,7 +204,6 @@ func (c *hednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models
|
||||
|
||||
func (c *hednsProvider) getDiff1DomainCorrections(dc *models.DomainConfig, zoneID uint64, records models.Records) ([]*models.Correction, error) {
|
||||
var corrections []*models.Correction
|
||||
var toCreate, toDelete, toModify diff.Changeset
|
||||
|
||||
differ := diff.New(dc)
|
||||
_, toCreate, toDelete, toModify, err := differ.IncrementalDiff(records)
|
||||
|
||||
@@ -69,38 +69,20 @@ func (api *hetznerProvider) EnsureZoneExists(domain string) error {
|
||||
return api.createZone(domain)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *hetznerProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
domain := dc.Name
|
||||
|
||||
// Get existing records
|
||||
existingRecords, err := api.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -57,12 +57,8 @@ func (n *HXClient) GetZoneRecords(domain string) (models.Records, error) {
|
||||
|
||||
}
|
||||
|
||||
// GetDomainCorrections gathers correctios that would bring n to match dc.
|
||||
func (n *HXClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *HXClient) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
|
||||
actual, err := n.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
@@ -71,19 +67,16 @@ func (n *HXClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr
|
||||
|
||||
//checkNSModifications(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, mod diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, mod, err = differ.IncrementalDiff(actual)
|
||||
_, create, del, mod, err := differ.IncrementalDiff(actual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -117,13 +117,9 @@ func soaToString(s soaValues) string {
|
||||
return fmt.Sprintf("refresh=%d retry=%d expire=%d negativettl=%d ttl=%d", s.Refresh, s.Retry, s.Expire, s.NegativeTTL, s.TTL)
|
||||
}
|
||||
|
||||
func (hp *hostingdeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zoneChanged := false
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
var err error
|
||||
|
||||
// TTL must be between (inclusive) 1m and 1y (in fact, a little bit more)
|
||||
for _, r := range dc.Records {
|
||||
@@ -134,13 +130,14 @@ func (hp *hostingdeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
r.TTL = 31556926
|
||||
}
|
||||
}
|
||||
|
||||
zoneChanged := false
|
||||
|
||||
zone, err := hp.getZone(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := hp.APIRecordsToStandardRecordsModel(dc.Name, zone.Records)
|
||||
|
||||
var create, del, mod diff.Changeset
|
||||
if !diff2.EnableDiff2 {
|
||||
_, create, del, mod, err = diff.New(dc).IncrementalDiff(records)
|
||||
@@ -320,10 +317,10 @@ func firstNonZero(items ...uint32) uint32 {
|
||||
}
|
||||
|
||||
func (hp *hostingdeProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// err := dc.Punycode()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
found, err := hp.getNameservers(dc.Name)
|
||||
if err != nil {
|
||||
|
||||
@@ -226,32 +226,24 @@ func checkRecords(records models.Records) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections finds the currently existing records and returns the corrections required to update them.
|
||||
func (api *inwxAPI) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
foundRecords, err := api.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
models.PostProcessRecords(foundRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
err = checkRecords(dc.Records)
|
||||
err := checkRecords(dc.Records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, mod diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, mod, err = differ.IncrementalDiff(foundRecords)
|
||||
_, create, del, mod, err := differ.IncrementalDiff(foundRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -122,33 +122,8 @@ func (api *linodeProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
return api.getRecordsForDomain(domainID, domain)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *linodeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
if api.domainIndex == nil {
|
||||
if err := api.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
domainID, ok := api.domainIndex[dc.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("'%s' not a zone in Linode account", dc.Name)
|
||||
}
|
||||
|
||||
existingRecords, err := api.getRecordsForDomain(domainID, dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *linodeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
// Linode doesn't allow selecting an arbitrary TTL, only a set of predefined values
|
||||
// We need to make sure we don't change it every time if it is as close as it's going to get
|
||||
// By experimentation, Linode always rounds up. 300 -> 300, 301 -> 3600.
|
||||
@@ -157,15 +132,25 @@ func (api *linodeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
record.TTL = fixTTL(record.TTL)
|
||||
}
|
||||
|
||||
var err error
|
||||
if api.domainIndex == nil {
|
||||
if err = api.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
domainID, ok := api.domainIndex[dc.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("'%s' not a zone in Linode account", dc.Name)
|
||||
}
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -156,29 +156,6 @@ func (c *APIClient) ListZones() ([]string, error) {
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
// NB(tal): To future-proof your code, all new providers should
|
||||
// implement GetDomainCorrections exactly as you see here
|
||||
// (byte-for-byte the same). In 3.0
|
||||
// we plan on using just the individual calls to GetZoneRecords,
|
||||
// PostProcessRecords, and so on.
|
||||
//
|
||||
// Currently every provider does things differently, which prevents
|
||||
// us from doing things like using GetZoneRecords() of a provider
|
||||
// to make convertzone work with all providers.
|
||||
|
||||
// GetDomainCorrections get the current and existing records,
|
||||
// post-process them, and generate corrections.
|
||||
func (c *APIClient) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
existing, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
clean := PrepFoundRecords(existing)
|
||||
PrepDesiredRecords(dc)
|
||||
return c.GenerateZoneRecordsCorrections(dc, clean)
|
||||
}
|
||||
|
||||
// GetZoneRecords gathers the DNS records and converts them to
|
||||
// dnscontrol's format.
|
||||
func (c *APIClient) GetZoneRecords(domain string) (models.Records, error) {
|
||||
@@ -235,11 +212,11 @@ func (c *APIClient) GetZoneRecords(domain string) (models.Records, error) {
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
//func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
//return recs
|
||||
//}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
@@ -248,8 +225,6 @@ func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
// provider. We try to do minimal changes otherwise it gets
|
||||
// confusing.
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" {
|
||||
@@ -266,9 +241,6 @@ func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
printer.Warnf("Loopia does not support TTL > 68 years. Setting %s from %d to 2147483647\n", rec.GetLabelFQDN(), rec.TTL)
|
||||
rec.TTL = 2147483647
|
||||
}
|
||||
// if rec.Type == "TXT" {
|
||||
// rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(systemcrash): Should do proper quoting.
|
||||
// }
|
||||
// if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||
// if !strings.HasSuffix(rec.GetTargetField(), ".loopia.se.") {
|
||||
// printer.Warnf("Loopia does not support changing apex NS records. Ignoring %s\n", rec.GetTargetField())
|
||||
@@ -293,18 +265,15 @@ func gatherAffectedLabels(groups map[models.RecordKey][]string) (labels map[stri
|
||||
return labels, msgs
|
||||
}
|
||||
|
||||
// GenerateZoneRecordsCorrections takes the desired and existing records
|
||||
// and produces a Correction list. The correction list is simply
|
||||
// a list of functions to call to actually make the desired
|
||||
// correction, and a message to output to the user when the change is
|
||||
// made.
|
||||
func (c *APIClient) GenerateZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
if c.Debug {
|
||||
debugRecords("GenerateZoneRecordsCorrections input:\n", existingRecords)
|
||||
}
|
||||
|
||||
// Normalize
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
PrepDesiredRecords(dc)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var keysToUpdate map[models.RecordKey][]string
|
||||
|
||||
@@ -94,25 +94,15 @@ func (l *luadnsProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (l *luadnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (l *luadnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
|
||||
checkNS(dc)
|
||||
|
||||
domainID, err := l.getDomainID(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records, err := l.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checkNS(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(records)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var corrs []*models.Correction
|
||||
|
||||
@@ -9,19 +9,17 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil"
|
||||
)
|
||||
|
||||
// GetDomainCorrections gets existing records, diffs them against existing, and returns corrections.
|
||||
func (client *msdnsProvider) GenerateDomainCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (client *msdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
var creates, dels, modifications diff.Changeset
|
||||
var err error
|
||||
if !diff2.EnableDiff2 {
|
||||
differ := diff.New(dc)
|
||||
_, creates, dels, modifications, err = differ.IncrementalDiff(foundRecords)
|
||||
_, creates, dels, modifications, err := differ.IncrementalDiff(foundRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||
)
|
||||
|
||||
@@ -70,31 +69,6 @@ func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSSe
|
||||
|
||||
// Section 3: Domain Service Provider (DSP) related functions
|
||||
|
||||
// NB(tal): To future-proof your code, all new providers should
|
||||
// implement GetDomainCorrections exactly as you see here
|
||||
// (byte-for-byte the same). In 3.0
|
||||
// we plan on using just the individual calls to GetZoneRecords,
|
||||
// PostProcessRecords, and so on.
|
||||
//
|
||||
// Currently every provider does things differently, which prevents
|
||||
// us from doing things like using GetZoneRecords() of a provider
|
||||
// to make convertzone work with all providers.
|
||||
|
||||
// GetDomainCorrections get the current and existing records,
|
||||
// post-process them, and generate corrections.
|
||||
func (client *msdnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
existing, err := client.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
clean := PrepFoundRecords(existing)
|
||||
PrepDesiredRecords(dc)
|
||||
return client.GenerateDomainCorrections(dc, clean)
|
||||
}
|
||||
|
||||
// GetZoneRecords gathers the DNS records and converts them to
|
||||
// dnscontrol's format.
|
||||
func (client *msdnsProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
@@ -119,24 +93,6 @@ func (client *msdnsProvider) GetZoneRecords(domain string) (models.Records, erro
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// PrepFoundRecords munges any records to make them compatible with
|
||||
// this provider. Usually this is a no-op.
|
||||
func PrepFoundRecords(recs models.Records) models.Records {
|
||||
// If there are records that need to be modified, removed, etc. we
|
||||
// do it here. Usually this is a no-op.
|
||||
return recs
|
||||
}
|
||||
|
||||
// PrepDesiredRecords munges any records to best suit this provider.
|
||||
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||
// Sort through the dc.Records, eliminate any that can't be
|
||||
// supported; modify any that need adjustments to work with the
|
||||
// provider. We try to do minimal changes otherwise it gets
|
||||
// confusing.
|
||||
|
||||
dc.Punycode()
|
||||
}
|
||||
|
||||
// NB(tlim): If we want to implement a registrar, refer to
|
||||
// http://go.microsoft.com/fwlink/?LinkId=288158
|
||||
// (Get-DnsServerZoneDelegation) for hints about which PowerShell
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
package namecheap
|
||||
|
||||
import "github.com/StackExchange/dnscontrol/v3/models"
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/rejectif"
|
||||
)
|
||||
|
||||
// AuditRecords returns a list of errors corresponding to the records
|
||||
// that aren't supported by this provider. If all records are
|
||||
// supported, an empty list is returned.
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
return nil
|
||||
a := rejectif.Auditor{}
|
||||
|
||||
a.Add("MX", rejectif.MxNull)
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasDoubleQuotes)
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
|
||||
@@ -126,24 +126,113 @@ func (n *namecheapProvider) GetZoneRecords(domain string) (models.Records, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// namecheap has this really annoying feature where they add some parking records if you have no records.
|
||||
// This causes a few problems for our purposes, specifically the integration tests.
|
||||
// lets detect that one case and pretend it is a no-op.
|
||||
if len(records.Hosts) == 2 {
|
||||
if records.Hosts[0].Type == "CNAME" &&
|
||||
strings.Contains(records.Hosts[0].Address, "parkingpage") &&
|
||||
records.Hosts[1].Type == "URL" {
|
||||
// return an empty zone
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Copying this from GetDomainCorrections. This seems redundent
|
||||
// with what toRecords() does. Leaving it out.
|
||||
// for _, r := range records.Hosts {
|
||||
// if r.Type == "SOA" {
|
||||
// continue
|
||||
// }
|
||||
// rec := &models.RecordConfig{
|
||||
// Type: r.Type,
|
||||
// TTL: uint32(r.TTL),
|
||||
// MxPreference: uint16(r.MXPref),
|
||||
// Original: r,
|
||||
// }
|
||||
// rec.SetLabel(r.Name, dc.Name)
|
||||
// switch rtype := r.Type; rtype { // #rtype_variations
|
||||
// case "TXT":
|
||||
// rec.SetTargetTXT(r.Address)
|
||||
// case "CAA":
|
||||
// rec.SetTargetCAAString(r.Address)
|
||||
// default:
|
||||
// rec.SetTarget(r.Address)
|
||||
// }
|
||||
// actual = append(actual, rec)
|
||||
// }
|
||||
|
||||
return toRecords(records, domain)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for the domain.
|
||||
func (n *namecheapProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
sld, tld := splitDomain(dc.Name)
|
||||
var records *nc.DomainDNSGetHostsResult
|
||||
var err error
|
||||
doWithRetry(func() error {
|
||||
records, err = n.client.DomainsDNSGetHosts(sld, tld)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// // GetDomainCorrections returns the corrections for the domain.
|
||||
// func (n *namecheapProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// dc.Punycode()
|
||||
// sld, tld := splitDomain(dc.Name)
|
||||
// var records *nc.DomainDNSGetHostsResult
|
||||
// var err error
|
||||
// doWithRetry(func() error {
|
||||
// records, err = n.client.DomainsDNSGetHosts(sld, tld)
|
||||
// return err
|
||||
// })
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
var actual []*models.RecordConfig
|
||||
// var actual []*models.RecordConfig
|
||||
|
||||
// // namecheap does not allow setting @ NS with basic DNS
|
||||
// dc.Filter(func(r *models.RecordConfig) bool {
|
||||
// if r.Type == "NS" && r.GetLabel() == "@" {
|
||||
// if !strings.HasSuffix(r.GetTargetField(), "registrar-servers.com.") {
|
||||
// printer.Println("\n", r.GetTargetField(), "Namecheap does not support changing apex NS records. Skipping.")
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
// return true
|
||||
// })
|
||||
|
||||
// // namecheap has this really annoying feature where they add some parking records if you have no records.
|
||||
// // This causes a few problems for our purposes, specifically the integration tests.
|
||||
// // lets detect that one case and pretend it is a no-op.
|
||||
// if len(dc.Records) == 0 && len(records.Hosts) == 2 {
|
||||
// if records.Hosts[0].Type == "CNAME" &&
|
||||
// strings.Contains(records.Hosts[0].Address, "parkingpage") &&
|
||||
// records.Hosts[1].Type == "URL" {
|
||||
// return nil, nil
|
||||
// }
|
||||
// }
|
||||
|
||||
// for _, r := range records.Hosts {
|
||||
// if r.Type == "SOA" {
|
||||
// continue
|
||||
// }
|
||||
// rec := &models.RecordConfig{
|
||||
// Type: r.Type,
|
||||
// TTL: uint32(r.TTL),
|
||||
// MxPreference: uint16(r.MXPref),
|
||||
// Original: r,
|
||||
// }
|
||||
// rec.SetLabel(r.Name, dc.Name)
|
||||
// switch rtype := r.Type; rtype { // #rtype_variations
|
||||
// case "TXT":
|
||||
// rec.SetTargetTXT(r.Address)
|
||||
// case "CAA":
|
||||
// rec.SetTargetCAAString(r.Address)
|
||||
// default:
|
||||
// rec.SetTarget(r.Address)
|
||||
// }
|
||||
// actual = append(actual, rec)
|
||||
// }
|
||||
|
||||
// // Normalize
|
||||
// models.PostProcessRecords(actual)
|
||||
|
||||
// return n.GetZoneRecordsCorrections(dc, actual)
|
||||
// }
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *namecheapProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// namecheap does not allow setting @ NS with basic DNS
|
||||
dc.Filter(func(r *models.RecordConfig) bool {
|
||||
@@ -156,50 +245,13 @@ func (n *namecheapProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mo
|
||||
return true
|
||||
})
|
||||
|
||||
// namecheap has this really annoying feature where they add some parking records if you have no records.
|
||||
// This causes a few problems for our purposes, specifically the integration tests.
|
||||
// lets detect that one case and pretend it is a no-op.
|
||||
if len(dc.Records) == 0 && len(records.Hosts) == 2 {
|
||||
if records.Hosts[0].Type == "CNAME" &&
|
||||
strings.Contains(records.Hosts[0].Address, "parkingpage") &&
|
||||
records.Hosts[1].Type == "URL" {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range records.Hosts {
|
||||
if r.Type == "SOA" {
|
||||
continue
|
||||
}
|
||||
rec := &models.RecordConfig{
|
||||
Type: r.Type,
|
||||
TTL: uint32(r.TTL),
|
||||
MxPreference: uint16(r.MXPref),
|
||||
Original: r,
|
||||
}
|
||||
rec.SetLabel(r.Name, dc.Name)
|
||||
switch rtype := r.Type; rtype { // #rtype_variations
|
||||
case "TXT":
|
||||
rec.SetTargetTXT(r.Address)
|
||||
case "CAA":
|
||||
rec.SetTargetCAAString(r.Address)
|
||||
default:
|
||||
rec.SetTarget(r.Address)
|
||||
}
|
||||
actual = append(actual, rec)
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
|
||||
var create, delete, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, delete, modify, err = differ.IncrementalDiff(actual)
|
||||
_, create, delete, modify, err := differ.IncrementalDiff(actual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -245,7 +297,14 @@ func toRecords(result *nc.DomainDNSGetHostsResult, origin string) ([]*models.Rec
|
||||
MxPreference: uint16(dnsHost.MXPref),
|
||||
Name: dnsHost.Name,
|
||||
}
|
||||
record.PopulateFromString(dnsHost.Type, dnsHost.Address, origin)
|
||||
record.SetLabel(dnsHost.Name, origin)
|
||||
|
||||
switch dnsHost.Type {
|
||||
case "MX":
|
||||
record.SetTargetMX(uint16(dnsHost.MXPref), dnsHost.Address)
|
||||
default:
|
||||
record.PopulateFromString(dnsHost.Type, dnsHost.Address, origin)
|
||||
}
|
||||
|
||||
records = append(records, &record)
|
||||
}
|
||||
|
||||
@@ -34,14 +34,10 @@ func (n *namedotcomProvider) GetZoneRecords(domain string) (models.Records, erro
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections gathers correctios that would bring n to match dc.
|
||||
func (n *namedotcomProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *namedotcomProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
|
||||
actual, err := n.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
checkNSModifications(dc)
|
||||
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" {
|
||||
@@ -49,11 +45,6 @@ func (n *namedotcomProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*m
|
||||
}
|
||||
}
|
||||
|
||||
checkNSModifications(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
@@ -193,19 +184,6 @@ func (n *namedotcomProvider) createRecord(rc *models.RecordConfig, domain string
|
||||
return err
|
||||
}
|
||||
|
||||
// // makeTxt encodes TxtStrings for sending in the CREATE/MODIFY API:
|
||||
// func encodeTxt(txts []string) string {
|
||||
// ans := txts[0]
|
||||
|
||||
// if len(txts) > 1 {
|
||||
// ans = ""
|
||||
// for _, t := range txts {
|
||||
// ans += `"` + strings.Replace(t, `"`, `\"`, -1) + `"`
|
||||
// }
|
||||
// }
|
||||
// return ans
|
||||
// }
|
||||
|
||||
// finds a string surrounded by quotes that might contain an escaped quote character.
|
||||
var quotedStringRegexp = regexp.MustCompile(`"((?:[^"\\]|\\.)*)"`)
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ func (api *netcupProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
for i := range records {
|
||||
existingRecords[i] = toRecordConfig(domain, &records[i])
|
||||
}
|
||||
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
@@ -67,16 +68,13 @@ func (api *netcupProvider) GetNameservers(domain string) ([]*models.Nameserver,
|
||||
})
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *netcupProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *netcupProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
domain := dc.Name
|
||||
|
||||
// no need for txtutil.SplitSingleLongTxt in function GetDomainCorrections
|
||||
// txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
// Setting the TTL is not supported for netcup
|
||||
for _, r := range dc.Records {
|
||||
r.TTL = 0
|
||||
@@ -91,26 +89,14 @@ func (api *netcupProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
|
||||
}
|
||||
dc.Records = newRecords
|
||||
|
||||
// Check existing set
|
||||
existingRecords, err := api.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
// no need for txtutil.SplitSingleLongTxt in function GetDomainCorrections
|
||||
// txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -176,31 +176,19 @@ func removeOtherApexNS(dc *models.DomainConfig) {
|
||||
dc.Records = newList
|
||||
}
|
||||
|
||||
func (n *netlifyProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *netlifyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
|
||||
err := dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records, err := n.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(records)
|
||||
removeOtherApexNS(dc)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(records)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -154,21 +154,10 @@ func (n *nsone) getDomainCorrectionsDNSSEC(domain, toggleDNSSEC string) *models.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
//dc.CombineMXs()
|
||||
|
||||
domain := dc.Name
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *nsone) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
corrections := []*models.Correction{}
|
||||
|
||||
// Get existing records
|
||||
existingRecords, err := n.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
domain := dc.Name
|
||||
|
||||
// add DNSSEC-related corrections
|
||||
if dnssecCorrections := n.getDomainCorrectionsDNSSEC(domain, dc.AutoDNSSEC); dnssecCorrections != nil {
|
||||
|
||||
@@ -202,25 +202,9 @@ func (o *oracleProvider) GetZoneRecords(zone string) (models.Records, error) {
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (o *oracleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domain := dc.Name
|
||||
|
||||
existingRecords, err := o.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (o *oracleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
var err error
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
// Ensure we don't emit changes for attempted modification of built-in apex NSs
|
||||
@@ -241,14 +225,13 @@ func (o *oracleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*model
|
||||
}
|
||||
}
|
||||
|
||||
var create, dels, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, dels, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, dels, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -294,7 +277,7 @@ func (o *oracleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*model
|
||||
return []*models.Correction{{
|
||||
Msg: desc,
|
||||
F: func() error {
|
||||
return o.patch(createRecords, deleteRecords, domain)
|
||||
return o.patch(createRecords, deleteRecords, dc.Name)
|
||||
},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
@@ -115,26 +115,15 @@ func (c *ovhProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
actual = append(actual, rec)
|
||||
}
|
||||
}
|
||||
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
func (c *ovhProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
var err error
|
||||
|
||||
err = dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actual, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *ovhProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
|
||||
var corrections []*models.Correction
|
||||
var err error
|
||||
if !diff2.EnableDiff2 {
|
||||
corrections, err = c.getDiff1DomainCorrections(dc, actual)
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,7 @@ var defaultNameServerNames = []string{
|
||||
"ns2.packetframe.com",
|
||||
}
|
||||
|
||||
type zone struct {
|
||||
type zoneInfo struct {
|
||||
ID string `json:"id"`
|
||||
Zone string `json:"zone"`
|
||||
Users []string `json:"users"`
|
||||
@@ -28,7 +28,7 @@ type zone struct {
|
||||
|
||||
type domainResponse struct {
|
||||
Data struct {
|
||||
Zones []zone `json:"zones"`
|
||||
Zones []zoneInfo `json:"zones"`
|
||||
} `json:"data"`
|
||||
Message string `json:"message"`
|
||||
Success bool `json:"success"`
|
||||
@@ -58,7 +58,7 @@ type domainRecord struct {
|
||||
}
|
||||
|
||||
func (api *packetframeProvider) fetchDomainList() error {
|
||||
api.domainIndex = map[string]zone{}
|
||||
api.domainIndex = map[string]zoneInfo{}
|
||||
dr := &domainResponse{}
|
||||
endpoint := "dns/zones"
|
||||
if err := api.get(endpoint, dr); err != nil {
|
||||
|
||||
@@ -19,7 +19,7 @@ type packetframeProvider struct {
|
||||
client *http.Client
|
||||
baseURL *url.URL
|
||||
token string
|
||||
domainIndex map[string]zone
|
||||
domainIndex map[string]zoneInfo
|
||||
}
|
||||
|
||||
// newPacketframe creates the provider.
|
||||
@@ -60,19 +60,28 @@ func (api *packetframeProvider) GetNameservers(domain string) ([]*models.Nameser
|
||||
return models.ToNameservers(defaultNameServerNames)
|
||||
}
|
||||
|
||||
// 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) getZone(domain string) (*zoneInfo, error) {
|
||||
if api.domainIndex == nil {
|
||||
if err := api.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
zone, ok := api.domainIndex[domain+"."]
|
||||
z, ok := api.domainIndex[domain+"."]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q not a zone in Packetframe account", domain)
|
||||
}
|
||||
|
||||
return &z, nil
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (api *packetframeProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||
|
||||
zone, err := api.getZone(domain)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no such zone %q in Packetframe account", domain)
|
||||
}
|
||||
|
||||
records, err := api.getRecords(zone.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load records for domain %q", domain)
|
||||
@@ -91,48 +100,21 @@ func (api *packetframeProvider) GetZoneRecords(domain string) (models.Records, e
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (api *packetframeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *packetframeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
zone, err := api.getZone(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
if api.domainIndex == nil {
|
||||
if err := api.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
zone, ok := api.domainIndex[dc.Name+"."]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no such zone %q in Packetframe account", dc.Name)
|
||||
}
|
||||
|
||||
records, err := api.getRecords(zone.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load records for domain %q", dc.Name)
|
||||
}
|
||||
|
||||
existingRecords := make([]*models.RecordConfig, len(records))
|
||||
|
||||
for i := range records {
|
||||
existingRecords[i] = toRc(dc, &records[i])
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, dels, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, dels, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, dels, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -75,26 +75,12 @@ func (c *porkbunProvider) GetNameservers(domain string) ([]*models.Nameserver, e
|
||||
return models.ToNameservers(defaultNS)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (c *porkbunProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
existingRecords, err := c.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (c *porkbunProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
// Block changes to NS records for base domain
|
||||
checkNSModifications(dc)
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
// Make sure TTL larger than the minimum TTL
|
||||
for _, record := range dc.Records {
|
||||
record.TTL = fixTTL(record.TTL)
|
||||
|
||||
@@ -2,11 +2,12 @@ package powerdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
"github.com/StackExchange/dnscontrol/v3/pkg/diff2"
|
||||
"github.com/mittwald/go-powerdns/apis/zones"
|
||||
"github.com/mittwald/go-powerdns/pdnshttp"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
@@ -44,19 +45,10 @@ func (dsp *powerdnsProvider) GetZoneRecords(domain string) (models.Records, erro
|
||||
return curRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corrections to update a domain.
|
||||
func (dsp *powerdnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
// get current zone records
|
||||
existing, err := dsp.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// post-process records
|
||||
if err := dc.Punycode(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models.PostProcessRecords(existing)
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (dsp *powerdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
// create record diff by group
|
||||
var err error
|
||||
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
@@ -158,10 +158,12 @@ 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) {
|
||||
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.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections gets the records of a zone and returns them in RecordConfig format.
|
||||
func (n None) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns corrections to update a domain.
|
||||
|
||||
@@ -134,6 +134,8 @@ func (r *route53Provider) ListZones() ([]string, error) {
|
||||
}
|
||||
|
||||
func (r *route53Provider) getZones() error {
|
||||
// TODO(tlim) This should memoize itself.
|
||||
|
||||
if r.zonesByDomain != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -223,6 +225,8 @@ func (r *route53Provider) GetZoneRecords(domain string) (models.Records, error)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -260,19 +264,15 @@ func (r *route53Provider) getZoneRecords(zone r53Types.HostedZone) (models.Recor
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
zone, err := r.getZone(dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRecords, err := r.getZoneRecords(zone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// update zone_id to current zone.id if not specified by the user
|
||||
for _, want := range dc.Records {
|
||||
if want.Type == "R53_ALIAS" && want.R53Alias["zone_id"] == "" {
|
||||
@@ -280,13 +280,14 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
|
||||
zone, err := r.getZone(dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// diff
|
||||
differ := diff.New(dc, getAliasMap)
|
||||
namesToUpdate, err := differ.ChangedGroups(existingRecords)
|
||||
|
||||
@@ -30,37 +30,19 @@ func (api *rwthProvider) GetNameservers(domain string) ([]*models.Nameserver, er
|
||||
return models.ToNameservers(RWTHDefaultNs)
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns a list of corretions to execute.
|
||||
func (api *rwthProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dc.Punycode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
domain := dc.Name
|
||||
|
||||
// Get existing records
|
||||
existingRecords, err := api.GetZoneRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
var create, del, modify diff.Changeset
|
||||
var differ diff.Differ
|
||||
if !diff2.EnableDiff2 {
|
||||
differ = diff.New(dc)
|
||||
} else {
|
||||
differ = diff.NewCompat(dc)
|
||||
}
|
||||
_, create, del, modify, err = differ.IncrementalDiff(existingRecords)
|
||||
_, create, del, modify, err := differ.IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -59,25 +59,25 @@ func (s *softlayerProvider) GetNameservers(domain string) ([]*models.Nameserver,
|
||||
return models.ToNameservers([]string{"ns1.softlayer.com", "ns2.softlayer.com"})
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (s *softlayerProvider) 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 to update a domain.
|
||||
func (s *softlayerProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
|
||||
domain, err := s.getDomain(&dc.Name)
|
||||
|
||||
// GetZoneRecords gets all the records for domainName and converts
|
||||
// them to model.RecordConfig.
|
||||
func (s *softlayerProvider) GetZoneRecords(domainName string) (models.Records, error) {
|
||||
domain, err := s.getDomain(&domainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actual, err := s.getExistingRecords(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (s *softlayerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
domain, err := s.getDomain(&dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -120,6 +120,8 @@ func (s *softlayerProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mo
|
||||
}
|
||||
|
||||
func (s *softlayerProvider) getDomain(name *string) (*datatypes.Dns_Domain, error) {
|
||||
// FIXME(tlim) Memoize this
|
||||
|
||||
domains, err := services.GetAccountService(s.Session).
|
||||
Filter(filter.Path("domains.name").Eq(name).Build()).
|
||||
Mask("resourceRecords").
|
||||
@@ -138,7 +140,7 @@ func (s *softlayerProvider) getDomain(name *string) (*datatypes.Dns_Domain, erro
|
||||
return &domains[0], nil
|
||||
}
|
||||
|
||||
func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.RecordConfig, error) {
|
||||
func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) (models.Records, error) {
|
||||
actual := []*models.RecordConfig{}
|
||||
|
||||
for _, record := range domain.ResourceRecords {
|
||||
@@ -190,9 +192,6 @@ func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) ([]
|
||||
actual = append(actual, recConfig)
|
||||
}
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(actual)
|
||||
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -94,25 +94,15 @@ func (n *transipProvider) ListZones() ([]string, error) {
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
func (n *transipProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
curRecords, err := n.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := dc.Punycode(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *transipProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, curRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
removeOtherNS(dc)
|
||||
|
||||
models.PostProcessRecords(curRecords)
|
||||
|
||||
if !diff2.EnableDiff2 {
|
||||
corrections, err := n.getCorrectionsUsingOldDiff(dc, curRecords)
|
||||
return corrections, err
|
||||
}
|
||||
|
||||
corrections, err := n.getCorrectionsUsingDiff2(dc, curRecords)
|
||||
return corrections, err
|
||||
}
|
||||
|
||||
@@ -109,9 +109,8 @@ func (api *vultrProvider) GetZoneRecords(domain string) (models.Records, error)
|
||||
return curRecords, nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections gets the corrections for a DomainConfig.
|
||||
func (api *vultrProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc.Punycode()
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (api *vultrProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, curRecords models.Records) ([]*models.Correction, error) {
|
||||
|
||||
for _, rec := range dc.Records {
|
||||
switch rec.Type { // #rtype_variations
|
||||
@@ -127,23 +126,16 @@ func (api *vultrProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
|
||||
}
|
||||
}
|
||||
|
||||
curRecords, err := api.GetZoneRecords(dc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
models.PostProcessRecords(curRecords)
|
||||
|
||||
var corrections []*models.Correction
|
||||
if !diff2.EnableDiff2 {
|
||||
differ := diff.New(dc)
|
||||
_, create, delete, modify, err := differ.IncrementalDiff(curRecords)
|
||||
_, create, toDelete, modify, err := differ.IncrementalDiff(curRecords)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, mod := range delete {
|
||||
for _, mod := range toDelete {
|
||||
id := mod.Existing.Original.(govultr.DomainRecord).ID
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: fmt.Sprintf("%s; Vultr RecordID: %v", mod.String(), id),
|
||||
|
||||
Reference in New Issue
Block a user