diff --git a/providers/_all/all.go b/providers/_all/all.go index b31bd8b9f..3479855bc 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -35,7 +35,6 @@ import ( _ "github.com/StackExchange/dnscontrol/v3/providers/netcup" _ "github.com/StackExchange/dnscontrol/v3/providers/netlify" _ "github.com/StackExchange/dnscontrol/v3/providers/ns1" - _ "github.com/StackExchange/dnscontrol/v3/providers/octodns" _ "github.com/StackExchange/dnscontrol/v3/providers/opensrs" _ "github.com/StackExchange/dnscontrol/v3/providers/oracle" _ "github.com/StackExchange/dnscontrol/v3/providers/ovh" diff --git a/providers/octodns/TESTING.md b/providers/octodns/TESTING.md deleted file mode 100644 index 05cf24490..000000000 --- a/providers/octodns/TESTING.md +++ /dev/null @@ -1,104 +0,0 @@ -# Testing: - -## Create the environment - -These variables are used in all other sections of this doc. - -```bash -export DNSCONFIGDIR=~/gitwork/fakeroot/ExternalDNS -export OCTCONFIGDIR=~/gitwork/octodns/dns -export SRCDIR=~/src/github.com/StackExchange/dnscontrol -``` - -## Code tests - -Unit tests: - -```bash -cd $SRCDIR/providers/octodns/octoyaml -go test -v -``` - -Integration tests: - -```bash -cd $SRCDIR/integrationTest -go test -v -verbose -provider OCTODNS -``` - -## Test against OctoDNS-Validate - -### Download OctoDNS: - -```bash -cd $DNSCONFIGDIR -mkdir dns -cd dns -virtualenv env -source env/bin/activate -pip install octodns -ln -s ~/gitwork/fakeroot/ExternalDNS/config config -``` - -### Modify dnsconfig.js - -Make a copy of dnsconfig.js and modify it to use OCTODNS as a provider. We did it this way: - -```bash -cd $DNSCONFIGDIR/dns -cp ../dnsconfig.js . -cp ../creds.json . -``` - -Add: - -```js -var OCT = NewDnsProvider("octodns", "OCTODNS"); -``` - -Add: - -```diff - DEFAULTS( - DnsProvider(SERVERFAULT, 0), -+ DnsProvider(OCT, 0), - NAMESERVER_TTL("2d"), - END); -``` - -Add: - -```diff - var NO_BIND = function(d) { - delete d.dnsProviders[SERVERFAULT]; -+ delete d.dnsProviders[OCT]; - }; -``` - -## Run the tests: - -### Step 1: Generate the files - -This builds the software then generates the yaml files in the config directory: - -```bash -(cd $SRCDIR && go install ) && cd $DNSCONFIGDIR/dns && rm -f config/*.yaml && dnscontrol push -providers=octodns -``` - -### Step 2: Run the validator: - -This runs octodns-validate against the YAMl files we generated. production.yaml should -list each domain. - -We create production.yaml like this: - -```bash -cd $DNSCONFIGDIR/dns && $SRCDIR/providers/octodns/mkprodyaml.sh -``` - -Now we can run the validation: - -```bash -cd $DNSCONFIGDIR/dns -cp $SRCDIR/providers/octodns/testdata/production.yaml config/. && env/bin/octodns-validate --log-stream-stdout -``` diff --git a/providers/octodns/auditrecords.go b/providers/octodns/auditrecords.go deleted file mode 100644 index 4dd078981..000000000 --- a/providers/octodns/auditrecords.go +++ /dev/null @@ -1,10 +0,0 @@ -package octodns - -import "github.com/StackExchange/dnscontrol/v3/models" - -// 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 -} diff --git a/providers/octodns/mkprodyaml.sh b/providers/octodns/mkprodyaml.sh deleted file mode 100755 index 5590339e2..000000000 --- a/providers/octodns/mkprodyaml.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Read the YAML files in the config directory and generate a production.yaml file. - -cat <production.yaml ---- -providers: - config: - class: octodns.provider.yaml.YamlProvider - directory: ./config -zones: -HERE - -( cd config && ls *.yaml ) | -grep -v '^provider.yaml$' | -sed 's/.\{4\}$//' | -awk '{ print " " $1 ":" ; print " sources:" ; print " - config" }' >>production.yaml diff --git a/providers/octodns/octodnsProvider.go b/providers/octodns/octodnsProvider.go deleted file mode 100644 index 3704b9436..000000000 --- a/providers/octodns/octodnsProvider.go +++ /dev/null @@ -1,186 +0,0 @@ -package octodns - -/* - -octodns - - Generate zonefiles suitiable for OctoDNS. - - The zonefiles are read and written to the directory octoconfig - - If the old octoconfig files are readable, we read them to determine - if an update is actually needed. - - The YAML input and output code is extremely complicated because - the format does not fit well with a statically typed language. - The YAML format changes drastically if the label has single - or multiple rtypes associated with it, and if there is a single - or multiple rtype data. - -*/ - -import ( - "bytes" - "encoding/json" - "fmt" - "log" - "os" - "path/filepath" - "strings" - - "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/diff" - "github.com/StackExchange/dnscontrol/v3/pkg/printer" - "github.com/StackExchange/dnscontrol/v3/pkg/txtutil" - "github.com/StackExchange/dnscontrol/v3/providers" - "github.com/StackExchange/dnscontrol/v3/providers/octodns/octoyaml" -) - -var features = providers.DocumentationNotes{ - providers.CanGetZones: providers.Unimplemented(), - providers.CanUsePTR: providers.Can(), - providers.CanUseSRV: providers.Can(), - providers.DocCreateDomains: providers.Cannot("Driver just maintains list of OctoDNS config files. You must manually create the master config files that refer these."), - providers.DocDualHost: providers.Cannot("Research is needed."), -} - -func initProvider(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) { - // config -- the key/values from creds.json - // meta -- the json blob from NewReq('name', 'TYPE', meta) - api := &octodnsProvider{ - directory: config["directory"], - } - if api.directory == "" { - api.directory = "config" - } - // Commented out because at this time api has no exported fields. - // if len(providermeta) != 0 { - // err := json.Unmarshal(providermeta, api) - // if err != nil { - // return nil, err - // } - // } - return api, nil -} - -func init() { - fns := providers.DspFuncs{ - Initializer: initProvider, - RecordAuditor: AuditRecords, - } - providers.RegisterDomainServiceProviderType("OCTODNS", fns, features) -} - -// octodnsProvider is the provider handle for the OctoDNS driver. -type octodnsProvider struct { - //DefaultNS []string `json:"default_ns"` - //DefaultSoa SoaInfo `json:"default_soa"` - //nameservers []*models.Nameserver - directory string -} - -// GetNameservers returns the nameservers for a domain. -func (c *octodnsProvider) GetNameservers(string) ([]*models.Nameserver, error) { - return nil, nil -} - -// GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (c *octodnsProvider) 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 a list of corrections to update a domain. -func (c *octodnsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - dc.Punycode() - // Phase 1: Copy everything to []*models.RecordConfig: - // expectedRecords < dc.Records[i] - // foundRecords < zonefile - // - // Phase 2: Do any manipulations: - // add NS - // manipulate SOA - // - // Phase 3: Convert to []diff.Records and compare: - // expectedDiffRecords < expectedRecords - // foundDiffRecords < foundRecords - // diff.Inc...(foundDiffRecords, expectedDiffRecords ) - - // Read foundRecords: - var foundRecords models.Records - zoneFileFound := true - zoneFileName := filepath.Join(c.directory, strings.Replace(strings.ToLower(dc.Name), "/", "_", -1)+".yaml") - foundFH, err := os.Open(zoneFileName) - if err != nil { - if os.IsNotExist(err) { - zoneFileFound = false - } else { - return nil, fmt.Errorf("can't open %s: %w", zoneFileName, err) - } - } else { - foundRecords, err = octoyaml.ReadYaml(foundFH, dc.Name) - if err != nil { - return nil, fmt.Errorf("can not get corrections: %w", err) - } - } - - // Normalize - models.PostProcessRecords(foundRecords) - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - - differ := diff.New(dc) - _, create, del, mod, err := differ.IncrementalDiff(foundRecords) - 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("GENERATE_CONFIGFILE: %s", dc.Name) - if zoneFileFound { - msg += "\n" - msg += buf.String() - } else { - msg += fmt.Sprintf(" (%d records)\n", len(create)) - } - corrections := []*models.Correction{} - if changes { - corrections = append(corrections, - &models.Correction{ - Msg: msg, - F: func() error { - printer.Printf("CREATING CONFIGFILE: %v\n", zoneFileName) - zf, err := os.Create(zoneFileName) - if err != nil { - log.Fatalf("Could not create zonefile: %v", err) - } - //err = WriteZoneFile(zf, dc.Records, dc.Name) - err = octoyaml.WriteYaml(zf, dc.Records, dc.Name) - if err != nil { - log.Fatalf("WriteZoneFile error: %v\n", err) - } - err = zf.Close() - if err != nil { - log.Fatalf("Closing: %v", err) - } - return nil - }, - }) - } - - return corrections, nil -} diff --git a/providers/octodns/octoyaml/js.go b/providers/octodns/octoyaml/js.go deleted file mode 100644 index 3e59b3b7b..000000000 --- a/providers/octodns/octoyaml/js.go +++ /dev/null @@ -1,89 +0,0 @@ -package octoyaml - -import ( - "encoding/json" - "os" - - "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/printer" - "github.com/StackExchange/dnscontrol/v3/pkg/transform" - "github.com/robertkrimen/otto" - _ "github.com/robertkrimen/otto/underscore" // required by otto -) - -// ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig. -func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) { - vm := otto.New() - - vm.Set("require", require) - vm.Set("REV", reverse) - - helperJs := GetHelpers(true) - // run helper script to prime vm and initialize variables - if _, err := vm.Run(helperJs); err != nil { - return nil, err - } - - // run user script - if _, err := vm.Run(script); err != nil { - return nil, err - } - - // export conf as string and unmarshal - value, err := vm.Run(`JSON.stringify(conf)`) - if err != nil { - return nil, err - } - str, err := value.ToString() - if err != nil { - return nil, err - } - conf := &models.DNSConfig{} - if err = json.Unmarshal([]byte(str), conf); err != nil { - return nil, err - } - return conf, nil -} - -// GetHelpers returns the filename of helpers.js, or the esc'ed version. -func GetHelpers(devMode bool) string { - d, err := os.ReadFile("../pkg/js/helpers.js") - if err != nil { - panic(err) - } - return string(d) -} - -func require(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) != 1 { - throw(call.Otto, "require takes exactly one argument") - } - file := call.Argument(0).String() - printer.Printf("requiring: %s\n", file) - data, err := os.ReadFile(file) - if err != nil { - throw(call.Otto, err.Error()) - } - _, err = call.Otto.Run(string(data)) - if err != nil { - throw(call.Otto, err.Error()) - } - return otto.TrueValue() -} - -func throw(vm *otto.Otto, str string) { - panic(vm.MakeCustomError("Error", str)) -} - -func reverse(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) != 1 { - throw(call.Otto, "REV takes exactly one argument") - } - dom := call.Argument(0).String() - rev, err := transform.ReverseDomainName(dom) - if err != nil { - throw(call.Otto, err.Error()) - } - v, _ := otto.ToValue(rev) - return v -} diff --git a/providers/octodns/octoyaml/parse_tests/001-single-a.js b/providers/octodns/octoyaml/parse_tests/001-single-a.js deleted file mode 100644 index 1e8ba6e37..000000000 --- a/providers/octodns/octoyaml/parse_tests/001-single-a.js +++ /dev/null @@ -1,6 +0,0 @@ -var REG = NewRegistrar("Third-Party","NONE"); -var CF = NewDnsProvider("bind", "BIND") -D("example.tld",REG,DnsProvider(CF), - DefaultTTL(301), - A("foo","1.2.3.4", TTL(301)) -); diff --git a/providers/octodns/octoyaml/parse_tests/001-single-a.json b/providers/octodns/octoyaml/parse_tests/001-single-a.json deleted file mode 100644 index a49dde6ea..000000000 --- a/providers/octodns/octoyaml/parse_tests/001-single-a.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "type":"A", - "name":"foo", - "target":"1.2.3.4", - "ttl":301 - } -] diff --git a/providers/octodns/octoyaml/parse_tests/001-single-a.yaml b/providers/octodns/octoyaml/parse_tests/001-single-a.yaml deleted file mode 100644 index c771c18f5..000000000 --- a/providers/octodns/octoyaml/parse_tests/001-single-a.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -foo: - ttl: 301 - type: A - value: 1.2.3.4 diff --git a/providers/octodns/octoyaml/parse_tests/002-multiple-a.js b/providers/octodns/octoyaml/parse_tests/002-multiple-a.js deleted file mode 100644 index 919678221..000000000 --- a/providers/octodns/octoyaml/parse_tests/002-multiple-a.js +++ /dev/null @@ -1,7 +0,0 @@ -var REG = NewRegistrar("Third-Party","NONE"); -var CF = NewDnsProvider("bind", "BIND") -D("example.tld",REG,DnsProvider(CF), - DefaultTTL(302), - A("foo","1.2.3.4"), - A("foo","1.2.3.5") -); diff --git a/providers/octodns/octoyaml/parse_tests/002-multiple-a.json b/providers/octodns/octoyaml/parse_tests/002-multiple-a.json deleted file mode 100644 index 6e531a3c3..000000000 --- a/providers/octodns/octoyaml/parse_tests/002-multiple-a.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - {"type":"A","name":"foo","target":"1.2.3.4","ttl":302}, - {"type":"A","name":"foo","target":"1.2.3.5","ttl":302} -] diff --git a/providers/octodns/octoyaml/parse_tests/002-multiple-a.yaml b/providers/octodns/octoyaml/parse_tests/002-multiple-a.yaml deleted file mode 100644 index 54909eb9e..000000000 --- a/providers/octodns/octoyaml/parse_tests/002-multiple-a.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -foo: - ttl: 302 - type: A - values: - - 1.2.3.4 - - 1.2.3.5 diff --git a/providers/octodns/octoyaml/parse_tests/003-complex.js b/providers/octodns/octoyaml/parse_tests/003-complex.js deleted file mode 100644 index ae3e971ac..000000000 --- a/providers/octodns/octoyaml/parse_tests/003-complex.js +++ /dev/null @@ -1,10 +0,0 @@ -var REG = NewRegistrar("Third-Party","NONE"); -var CF = NewDnsProvider("bind", "BIND") -D("example.tld",REG,DnsProvider(CF), - DefaultTTL(303), - A("one","1.2.3.3"), - A("foo","1.2.3.4"), - A("foo","1.2.3.5"), - MX("foo", 10, "mx1.example.com."), - MX("foo", 10, "mx2.example.com.") -); diff --git a/providers/octodns/octoyaml/parse_tests/003-complex.json b/providers/octodns/octoyaml/parse_tests/003-complex.json deleted file mode 100644 index b939f65fc..000000000 --- a/providers/octodns/octoyaml/parse_tests/003-complex.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - {"type":"A","name":"foo","target":"1.2.3.4","ttl":303}, - {"type":"A","name":"foo","target":"1.2.3.5","ttl":303}, - {"type":"MX","name":"foo","target":"mx1.example.com.","ttl":303,"mxpreference":10}, - {"type":"MX","name":"foo","target":"mx2.example.com.","ttl":303,"mxpreference":10}, - {"type":"A","name":"one","target":"1.2.3.3","ttl":303} -] diff --git a/providers/octodns/octoyaml/parse_tests/003-complex.yaml b/providers/octodns/octoyaml/parse_tests/003-complex.yaml deleted file mode 100644 index 1d4a8882f..000000000 --- a/providers/octodns/octoyaml/parse_tests/003-complex.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -foo: -- ttl: 303 - type: A - values: - - 1.2.3.4 - - 1.2.3.5 -- ttl: 303 - type: MX - values: - - priority: 10 - value: mx1.example.com. - - priority: 10 - value: mx2.example.com. -one: - ttl: 303 - type: A - value: 1.2.3.3 diff --git a/providers/octodns/octoyaml/parse_tests/004-doc-example1.json b/providers/octodns/octoyaml/parse_tests/004-doc-example1.json deleted file mode 100644 index e2ab0f40e..000000000 --- a/providers/octodns/octoyaml/parse_tests/004-doc-example1.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - {"type":"CNAME","name":"*","target":"www.example.com."}, - {"type":"A","name":"@","target":"1.2.3.4","ttl":304}, - {"type":"A","name":"@","target":"1.2.3.5","ttl":304}, - {"type":"A","name":"www","target":"1.2.3.4","ttl":304}, - {"type":"A","name":"www","target":"1.2.3.5","ttl":304}, - {"type":"A","name":"www.sub","target":"1.2.3.6","ttl":304}, - {"type":"A","name":"www.sub","target":"1.2.3.7","ttl":304} -] diff --git a/providers/octodns/octoyaml/parse_tests/004-doc-example1.yaml b/providers/octodns/octoyaml/parse_tests/004-doc-example1.yaml deleted file mode 100644 index d54424353..000000000 --- a/providers/octodns/octoyaml/parse_tests/004-doc-example1.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -'': - type: A - ttl: 304 - values: - - 1.2.3.4 - - 1.2.3.5 -'*': - type: CNAME - value: www.example.com. -www: - type: A - ttl: 304 - values: - - 1.2.3.4 - - 1.2.3.5 -www.sub: - type: A - ttl: 304 - values: - - 1.2.3.6 - - 1.2.3.7 diff --git a/providers/octodns/octoyaml/parse_tests/005-doc-example2.json b/providers/octodns/octoyaml/parse_tests/005-doc-example2.json deleted file mode 100644 index 002e4e179..000000000 --- a/providers/octodns/octoyaml/parse_tests/005-doc-example2.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"type":"A","name":"@","target":"1.2.3.4","ttl":305}, - {"type":"A","name":"@","target":"1.2.3.5","ttl":305}, - {"type":"MX","name":"@","target":"mx1.example.com.","ttl":305,"mxpreference":10}, - {"type":"MX","name":"@","target":"mx2.example.com.","ttl":305,"mxpreference":10} -] diff --git a/providers/octodns/octoyaml/parse_tests/005-doc-example2.yaml b/providers/octodns/octoyaml/parse_tests/005-doc-example2.yaml deleted file mode 100644 index 5bae18ba9..000000000 --- a/providers/octodns/octoyaml/parse_tests/005-doc-example2.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -'': - - type: A - ttl: 305 - values: - - 1.2.3.4 - - 1.2.3.5 - - type: MX - ttl: 305 - values: - - priority: 10 - value: mx1.example.com. - - priority: 10 - value: mx2.example.com. diff --git a/providers/octodns/octoyaml/parse_tests/006-apex.json b/providers/octodns/octoyaml/parse_tests/006-apex.json deleted file mode 100644 index e374e880a..000000000 --- a/providers/octodns/octoyaml/parse_tests/006-apex.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "type":"A", - "name":"@", - "target":"1.2.3.4", - "ttl":306 - } -] - diff --git a/providers/octodns/octoyaml/parse_tests/006-apex.yaml b/providers/octodns/octoyaml/parse_tests/006-apex.yaml deleted file mode 100644 index 5ed5747b3..000000000 --- a/providers/octodns/octoyaml/parse_tests/006-apex.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -'': - type: A - ttl: 306 - value: 1.2.3.4 diff --git a/providers/octodns/octoyaml/parse_tests/007-apex-quote.js b/providers/octodns/octoyaml/parse_tests/007-apex-quote.js deleted file mode 100644 index 47a7013cc..000000000 --- a/providers/octodns/octoyaml/parse_tests/007-apex-quote.js +++ /dev/null @@ -1,12 +0,0 @@ -// FYI: go-yaml writes an empty string as ""; python's yaml writes an empty string as "". -// For that reason: -// 006-apex: tests YAML -> JSON. -// 007-apex-quote: tests JS -> YAML -> JSON -// It would be nice if go-yaml has an option to write '' instead of "". - -var REG = NewRegistrar("Third-Party","NONE"); -var CF = NewDnsProvider("bind", "BIND") -D("example.tld",REG,DnsProvider(CF), - DefaultTTL(307), - A("@","1.2.3.4") -); diff --git a/providers/octodns/octoyaml/parse_tests/007-apex-quote.json b/providers/octodns/octoyaml/parse_tests/007-apex-quote.json deleted file mode 100644 index 5f6620334..000000000 --- a/providers/octodns/octoyaml/parse_tests/007-apex-quote.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "type":"A", - "name":"@", - "target":"1.2.3.4", - "ttl":307 - } -] diff --git a/providers/octodns/octoyaml/parse_tests/007-apex-quote.yaml b/providers/octodns/octoyaml/parse_tests/007-apex-quote.yaml deleted file mode 100644 index 01ca44b38..000000000 --- a/providers/octodns/octoyaml/parse_tests/007-apex-quote.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -"": - ttl: 307 - type: A - value: 1.2.3.4 diff --git a/providers/octodns/octoyaml/read.go b/providers/octodns/octoyaml/read.go deleted file mode 100644 index 0b9cf8799..000000000 --- a/providers/octodns/octoyaml/read.go +++ /dev/null @@ -1,269 +0,0 @@ -package octoyaml - -/* -This module handles reading OctoDNS yaml files. Sadly the YAML files -are so entirely flexible that parsing them is a nighmare. We UnMarshalYAML -them into a slice of interfaces mapped to interfaces, then use reflection -to walk the tree, interpreting what we find along the way. As we collect -data we output models.RecordConfig objects. -*/ - -import ( - "fmt" - "io" - "reflect" - "strconv" - - "github.com/StackExchange/dnscontrol/v3/models" - yaml "gopkg.in/yaml.v2" -) - -// ReadYaml parses a yaml input and returns a list of RecordConfigs -func ReadYaml(r io.Reader, origin string) (models.Records, error) { - results := models.Records{} - - // Slurp the YAML into a string. - ydata, err := io.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("can not read yaml filehandle: %w", err) - } - - // Unmarshal the mystery data into a structure we can relect into. - var mysterydata map[string]interface{} - err = yaml.Unmarshal(ydata, &mysterydata) - if err != nil { - return nil, fmt.Errorf("could not unmarshal yaml: %w", err) - } - //printer.Printf("ReadYaml: mysterydata == %v\n", mysterydata) - - // Traverse every key/value pair. - for k, v := range mysterydata { // Each label - // k, v: k is the label, v is everything we know about the label. - // In other code, k1, v2 refers to one level deeper, k3, k3 refers to - // one more level deeper, and so on. - //printer.Printf("ReadYaml: NEXT KEY\n") - //printer.Printf("ReadYaml: KEY=%s v.(type)=%s\n", k, reflect.TypeOf(v).String()) - switch v.(type) { - case map[interface{}]interface{}: - // The value is itself a map. This means we have a label with - // with one or more records, each of them are all the same rtype. - // parseLeaf will handle both of these forms: - // For example, this: - // 'www': - // type: A - // values: - // - 1.2.3.4 - // - 1.2.3.5 - // or - // 'www': - // type: CNAME - // value: foo.example.com. - results, err = parseLeaf(results, k, v, origin) - if err != nil { - return results, fmt.Errorf("leaf (%v) error: %w", v, err) - } - case []interface{}: - // The value is a list. This means we have a label with - // multiple records, each of them may be different rtypes. - // We need to call parseLeaf() once for each rtype. - // For example, this: - // 'www': - // - type: A - // values: - // - 1.2.3.4 - // - 1.2.3.5 - // - type: MX - // values: - // - priority: 10 - // value: mx1.example.com. - // - priority: 10 - // value: mx2.example.com. - for i, v3 := range v.([]interface{}) { // All the label's list - _ = i - //printer.Printf("ReadYaml: list key=%s i=%d v3.(type)=%s\n", k, i, typeof(v3)) - switch v3.(type) { - case map[interface{}]interface{}: - //printer.Printf("ReadYaml: v3=%v\n", v3) - results, err = parseLeaf(results, k, v3, origin) - if err != nil { - return results, fmt.Errorf("leaf v3=%v: %w", v3, err) - } - default: - return nil, fmt.Errorf("unknown type in list3: k=%s v.(type)=%T v=%v", k, v, v) - } - } - - default: - return nil, fmt.Errorf("unknown type in list1: k=%s v.(type)=%T v=%v", k, v, v) - } - } - - sortRecs(results, origin) - //printer.Printf("ReadYaml: RESULTS=%v\n", results) - return results, nil -} - -func parseLeaf(results models.Records, k string, v interface{}, origin string) (models.Records, error) { - var rType, rTarget string - var rTTL uint32 - rTargets := []string{} - var someresults models.Records - for k2, v2 := range v.(map[interface{}]interface{}) { // All the label's items - // printer.Printf("ReadYaml: ifs tk2=%s tv2=%s len(rTargets)=%d\n", typeof(k2), typeof(v2), len(rTargets)) - if typeof(k2) == "string" && (typeof(v2) == "string" || typeof(v2) == "int") { - // The 2nd level key is a string, and the 2nd level value is a string or int. - // Here are 3 examples: - // type: CNAME - // value: foo.example.com. - // ttl: 3 - //printer.Printf("parseLeaf: k2=%s v2=%v\n", k2, v2) - switch k2.(string) { - case "type": - rType = v2.(string) - case "ttl": - var err error - rTTL, err = decodeTTL(v2) - if err != nil { - return nil, fmt.Errorf("parseLeaf: can not parse ttl (%v)", v2) - } - case "value": - rTarget = v2.(string) - case "values": - switch v2.(type) { - case string: - rTarget = v2.(string) - default: - return nil, fmt.Errorf("parseLeaf: unknown type in values: rtpe=%s k=%s k2=%s v2.(type)=%T v2=%v", rType, k, k2, v2, v2) - } - default: - panic("Should not happen") - } - } else if typeof(k2) == "string" && typeof(v2) == "[]interface {}" { - // The 2nd level key is a string, and the 2nd level value is a list. - someresults = nil - for _, v3 := range v2.([]interface{}) { - switch v3.(type) { - case string: - // Example: - // values: - // - 1.2.3.1 - // - 1.2.3.2 - // - 1.2.3.3 - // We collect all the values for later, when we'll need to generate - // one RecordConfig for each value. - //printer.Printf("parseLeaf: s-append %s\n", v3.(string)) - rTargets = append(rTargets, v3.(string)) - case map[interface{}]interface{}: - // Example: - // values: - // - priority: 10 - // value: mx1.example.com. - // - priority: 10 - // value: mx2.example.com. - // We collect the individual values. When we are done with this level, - // we should have enough to generate a single RecordConfig. - newRc := newRecordConfig(k, rType, "", rTTL, origin) - for k4, v4 := range v3.(map[interface{}]interface{}) { - //printer.Printf("parseLeaf: k4=%s v4=%s\n", k4, v4) - switch k4.(string) { - case "priority": // MX,SRV - priority := uint16(v4.(int)) - newRc.MxPreference = priority - newRc.SrvPriority = priority - // Assign it to both places. We'll zap the wrong one later. - case "weight": // SRV - newRc.SrvWeight = uint16(v4.(int)) - case "port": // SRV - newRc.SrvPort = uint16(v4.(int)) - case "value": // MX - newRc.SetTarget(v4.(string)) - } - } - //printer.Printf("parseLeaf: append %v\n", newRc) - someresults = append(someresults, newRc) - default: - return nil, fmt.Errorf("parseLeaf: unknown type in map: rtype=%s k=%s v3.(type)=%T v3=%v", rType, k, v3, v3) - } - } - } else { - return nil, fmt.Errorf("parseLeaf: unknown type in level 2: k=%s k2=%s v.2(type)=%T v2=%v", k, k2, v2, v2) - } - } - // printer.Printf("parseLeaf: Target=(%v)\n", rTarget) - // printer.Printf("parseLeaf: len(rTargets)=%d\n", len(rTargets)) - // printer.Printf("parseLeaf: len(someresults)=%d\n", len(someresults)) - - // We've now looped through everything about one label. Make the RecordConfig(s). - - if len(someresults) > 0 { - // We have many results. Generate a RecordConfig for each one. - for _, r := range someresults { - r.Type = rType - r.TTL = rTTL - results = append(results, r) - // Earlier we didn't know what the priority was for. Now that we know the rType, - // we zap the wrong one. - switch r.Type { - case "MX": - r.SrvPriority = 0 - case "SRV": - r.MxPreference = 0 - default: - panic("ugh") - } - } - } else if rTarget != "" && len(rTargets) == 0 { - // The file used "value". Generate a single RecordConfig - //printer.Printf("parseLeaf: 1-newRecordConfig(%v, %v, %v, %v, %v)\n", k, rType, rTarget, rTTL, origin) - results = append(results, newRecordConfig(k, rType, rTarget, rTTL, origin)) - } else { - // The file used "values" so now we must generate a RecordConfig for each value. - for _, target := range rTargets { - //printer.Printf("parseLeaf: 3-newRecordConfig(%v, %v, %v, %v, %v)\n", k, rType, target, rTTL, origin) - results = append(results, newRecordConfig(k, rType, target, rTTL, origin)) - } - } - return results, nil -} - -// newRecordConfig is a RecordConfig factory. -func newRecordConfig(rname, rtype, target string, ttl uint32, origin string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: rtype, - TTL: ttl, - } - rc.SetLabel(rname, origin) - switch rtype { - case "SPF", "TXT": - rc.SetTargetTXT(target) - default: - rc.SetTarget(target) - } - return rc -} - -// typeof returns a string that indicates v's type: -func typeof(v interface{}) string { - // Cite: https://stackoverflow.com/a/20170555/71978 - return reflect.TypeOf(v).String() -} - -// decodeTTL decodes an interface into a TTL value. -// This is useful when you don't know if a TTL arrived as a string or int. -func decodeTTL(ttl interface{}) (uint32, error) { - switch ttl.(type) { - case uint32: - return ttl.(uint32), nil - case string: - s := ttl.(string) - t, err := strconv.ParseUint(s, 10, 32) - return uint32(t), fmt.Errorf("decodeTTL failed to parse (%s): %w", s, err) - case int: - i := ttl.(int) - if i < 0 { - return 0, fmt.Errorf("ttl cannot be negative (%d)", i) - } - return uint32(i), nil - } - panic("I don't know what type this TTL is") -} diff --git a/providers/octodns/octoyaml/rw_test.go b/providers/octodns/octoyaml/rw_test.go deleted file mode 100644 index dba98322d..000000000 --- a/providers/octodns/octoyaml/rw_test.go +++ /dev/null @@ -1,186 +0,0 @@ -package octoyaml - -/* - -Test - DSL -> yaml - YAML -> JSON - - 001-test.js - 001-test.yaml - 001-test.json -*/ - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path/filepath" - "testing" - "unicode" - - testifyrequire "github.com/stretchr/testify/require" - "github.com/tdewolff/minify/v2" - minjson "github.com/tdewolff/minify/v2/json" -) - -const ( - testDir = "octodns/octoyaml/parse_tests" - errorDir = "octodns/octoyaml/error_tests" -) - -func init() { - os.Chdir("../..") // go up a directory so we helpers.js is in a consistent place. -} - -func TestYamlWrite(t *testing.T) { - - // Read a .JS and make sure we can generate the expected YAML. - - files, err := os.ReadDir(testDir) - if err != nil { - t.Fatal(err) - } - for _, f := range files { - - // Run JS -> conf - - // run all js files that start with a number. Skip others. - if filepath.Ext(f.Name()) != ".js" || !unicode.IsNumber(rune(f.Name()[0])) { - continue - } - - m := minify.New() - m.AddFunc("json", minjson.Minify) - - t.Run(f.Name(), func(t *testing.T) { - fname := filepath.Join(testDir, f.Name()) - fmt.Printf("Filename: %v\n", fname) - content, err := os.ReadFile(fname) - if err != nil { - t.Fatal(err) - } - conf, err := ExecuteJavascript(string(content), true) - if err != nil { - t.Fatal(err) - } - basename := f.Name()[:len(f.Name())-3] // Remove ".js" - - // Run conf -> YAML - - actualYAML := bytes.NewBuffer([]byte{}) - dom := conf.FindDomain("example.tld") - if dom == nil { - panic(fmt.Sprintf("FILE %s does not mention domain '%s'", f.Name(), "example.tld")) - } - - err = WriteYaml(actualYAML, conf.FindDomain("example.tld").Records, "example.tld") - if err != nil { - t.Fatal(err) - } - - // Read expected YAML - - expectedFile := filepath.Join(testDir, basename+".yaml") - expectedData, err := os.ReadFile(expectedFile) - if err != nil { - t.Fatal(err) - } - expectedYAML := expectedData - - // Compare YAML and expectedData - - if string(expectedYAML) != actualYAML.String() { - t.Error("Expected and actual YAML don't match") - t.Log("Expected:", string(expectedYAML)) - t.Log("Actual :", actualYAML.String()) - } - - }) - } -} - -func TestYamlRead(t *testing.T) { - - // Read a .YAML and make sure it matches the RecordConfig (.JSON). - - minifyFlag := true - - files, err := os.ReadDir(testDir) - if err != nil { - t.Fatal(err) - } - for _, f := range files { - // run all yaml files that start with a number. Skip others. - if filepath.Ext(f.Name()) != ".yaml" || !unicode.IsNumber(rune(f.Name()[0])) { - continue - } - basename := f.Name()[:len(f.Name())-5] // remove ".yaml" - - m := minify.New() - m.AddFunc("json", minjson.Minify) - - t.Run(f.Name(), func(t *testing.T) { - - // Parse YAML - - content, err := os.ReadFile(filepath.Join(testDir, f.Name())) - if err != nil { - if os.IsNotExist(err) { - content = nil - } else { - t.Fatal(err) - } - } - recs, err := ReadYaml(bytes.NewBufferString(string(content)), "example.tld") - if err != nil { - t.Fatal(err) - } - //fmt.Printf("DEBUG: CONTENT=%s\n", string(content)) - //fmt.Printf("DEBUG: RECS=%v\n", recs) - - // YAML -> JSON - - actualJSON, err := json.MarshalIndent(recs, "", " ") - if err != nil { - t.Fatal(err) - } - if minifyFlag { - // fmt.Printf("DEBUG: actualJSON-full: %s\n", actualJSON) - actualJSON, err = m.Bytes("json", actualJSON) - } - if err != nil { - t.Fatal(err) - } - // fmt.Printf("DEBUG: actualJSON-mini: %s\n", actualJSON) - - // Read expected JSON - expectedFile := filepath.Join(testDir, basename+".json") - expectedData, err := os.ReadFile(expectedFile) - if err != nil { - if os.IsNotExist(err) { - fmt.Println("SKIPPING") - t.Log("Skipping (no .json)") - return - } - t.Fatal(err) - } - var expectedJSON string - if minifyFlag { - expectedJSON, err = m.String("json", string(expectedData)) - } else { - expectedJSON = string(expectedData) - } - if err != nil { - t.Fatal(err) - } - - //fmt.Printf("DEBUG: EXPECTED=%s\n", string(expectedJSON)) - //fmt.Printf("DEBUG: ACTUAL =%s\n", string(actualJSON)) - - es, as := string(expectedJSON), string(actualJSON) - testifyrequire.JSONEqf(t, es, as, "EXPECTING %q = \n```\n%s\n```", expectedFile, as) - }) - } -} diff --git a/providers/octodns/octoyaml/sort.go b/providers/octodns/octoyaml/sort.go deleted file mode 100644 index fe0fae9c3..000000000 --- a/providers/octodns/octoyaml/sort.go +++ /dev/null @@ -1,136 +0,0 @@ -package octoyaml - -import ( - "bytes" - "fmt" - "log" - "net" - "sort" - - "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/natsort" - "github.com/miekg/dns/dnsutil" -) - -type genYamlData struct { - Origin string - DefaultTTL uint32 - Records models.Records -} - -func sortRecs(recs models.Records, origin string) { - z := &genYamlData{ - Origin: dnsutil.AddOrigin(origin, "."), - Records: recs, - } - sort.Sort(z) -} - -func (z *genYamlData) Len() int { return len(z.Records) } -func (z *genYamlData) Swap(i, j int) { z.Records[i], z.Records[j] = z.Records[j], z.Records[i] } -func (z *genYamlData) Less(i, j int) bool { - a, b := z.Records[i], z.Records[j] - compA, compB := a.GetLabel(), b.GetLabel() - if compA != compB { - if compA == z.Origin+"." { - compA = "@" - } - if compB == z.Origin+"." { - compB = "@" - } - return zoneLabelLess(compA, compB) - } - rrtypeA, rrtypeB := a.Type, b.Type - if rrtypeA != rrtypeB { - return zoneRrtypeLess(rrtypeA, rrtypeB) - } - switch rrtypeA { // #rtype_variations - case "NS", "TXT", "TLSA": - // pass through. - case "A": - ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField()) - ipa, ipb := ta2.To4(), tb2.To4() - if ipa == nil || ipb == nil { - log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2) - } - return bytes.Compare(ipa, ipb) == -1 - case "AAAA": - ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField()) - ipa, ipb := ta2.To16(), tb2.To16() - return bytes.Compare(ipa, ipb) == -1 - case "MX": - pa, pb := a.MxPreference, b.MxPreference - return pa < pb - case "SRV": - pa, pb := a.SrvPort, b.SrvPort - if pa != pb { - return pa < pb - } - pa, pb = a.SrvPriority, b.SrvPriority - if pa != pb { - return pa < pb - } - pa, pb = a.SrvWeight, a.SrvWeight - if pa != pb { - return pa < pb - } - case "PTR": - pa, pb := a.GetTargetField(), b.GetTargetField() - if pa != pb { - return pa < pb - } - case "CAA": - // sort by tag - pa, pb := a.CaaTag, b.CaaTag - if pa != pb { - return pa < pb - } - // then flag - fa, fb := a.CaaFlag, b.CaaFlag - if fa != fb { - // flag set goes before ones without flag set - return fa > fb - } - default: - panic(fmt.Sprintf("genYamlData Less: unimplemented rtype %v", a.Type)) - // We panic so that we quickly find any switch statements - // that have not been updated for a new RR type. - } - return a.GetTargetSortable() < b.GetTargetSortable() -} - -func zoneLabelLess(a, b string) bool { - return natsort.Less(a, b) - // octodns-validate wants a "natural sort" (i.e. foo10 comes after foo3). - // We emulate this with the natsort package. - // If you need to disable that validatation: - // Edit env/lib/python2.7/site-packages/octodns/yaml.py - // Change line 27: OLD: if key != expected - // NEW: if False and key != expected -} - -func zoneRrtypeLess(a, b string) bool { - // Compare two RR types for the purpose of sorting the RRs in a Zone. - - // If they are equal, we are done. All other code is simplified - // because we can assume a!=b. - if a == b { - return false - } - - // List SOAs, then NSs, then all others. - // i.e. SOA is always less. NS is less than everything but SOA. - if a == "SOA" { - return true - } - if b == "SOA" { - return false - } - if a == "NS" { - return true - } - if b == "NS" { - return false - } - return a < b -} diff --git a/providers/octodns/octoyaml/write.go b/providers/octodns/octoyaml/write.go deleted file mode 100644 index aa54a4652..000000000 --- a/providers/octodns/octoyaml/write.go +++ /dev/null @@ -1,321 +0,0 @@ -package octoyaml - -import ( - "fmt" - "io" - "sort" - "strings" - - "github.com/StackExchange/dnscontrol/v3/models" - "github.com/miekg/dns/dnsutil" - yaml "gopkg.in/yaml.v2" -) - -// WriteYaml outputs a yaml version of a list of RecordConfig. -func WriteYaml(w io.Writer, records models.Records, origin string) error { - if len(records) == 0 { - return nil - } - - // Pick the most common TTL as the default so we can - // write the fewest "ttl:" lines. - defaultTTL := mostCommonTTL(records) - - // Make a copy of the records, since we want to sort and muck with them. - recsCopy := models.Records{} - recsCopy = append(recsCopy, records...) - for _, r := range recsCopy { - if r.GetLabel() == "@" { - //r.Name = "" - r.UnsafeSetLabelNull() - } - } - - z := &genYamlData{ - Origin: dnsutil.AddOrigin(origin, "."), - DefaultTTL: defaultTTL, - Records: recsCopy, - } - - // Sort in the weird order that OctoDNS expects: - sort.Sort(z) - - // Generate the YAML: - fmt.Fprintln(w, "---") - yb, err := yaml.Marshal(z.genInterfaceList(w)) - if err != nil { - return err - } - _, err = w.Write(yb) - - return err -} - -// genInterfaceList outputs YAML ordered slices for the entire zone. -// Each item in the list is an interface that will MarshallYAML to -// the desired output. -func (z *genYamlData) genInterfaceList(w io.Writer) yaml.MapSlice { - var yam yaml.MapSlice - // Group the records by label. - order, groups := z.Records.GroupedByLabel() - // For each group, generate the YAML. - for _, label := range order { - group := groups[label] - // Within the group, sort the similar Types together: - sort.SliceStable(group, func(i, j int) bool { return zoneRrtypeLess(group[i].Type, group[j].Type) }) - // Generate the YAML records: - yam = append(yam, oneLabel(group)) - } - return yam -} - -// "simple" records are when a label has a single rtype. -// It may have a single (simple) or multiple (many) values. - -// Used to generate: -// -// label: -// type: A -// value: 1.2.3.4 -type simple struct { - TTL uint32 `yaml:"ttl,omitempty"` - Type string `yaml:"type"` - Value string `yaml:"value"` -} - -// Used to generate: -// -// label: -// type: A -// values: -// - 1.2.3.4 -// - 2.3.4.5 -type many struct { - TTL uint32 `yaml:"ttl,omitempty"` - Type string `yaml:"type"` - Values []string `yaml:"values"` -} - -// complexItems are when a single label has multiple rtypes -// associated with it. For example, a label with both an A and MX record. -type complexItems []interface{} - -// Used to generate a complex item with either a single value or multiple values: -// 'thing': >> complexVals -// - type: CNAME -// value: newplace.example.com. << value -// -// 'www': -// - type: A -// values: -// - 1.2.3.4 << values -// - 1.2.3.5 << values -// - type: MX -// values: -// - priority: 10 << fields -// value: mx1.example.com. << fields -// - priority: 10 << fields -// value: mx2.example.com. << fields -type complexVals struct { - TTL uint32 `yaml:"ttl,omitempty"` - Type string `yaml:"type"` - Value string `yaml:"value,omitempty"` - Values []string `yaml:"values,omitempty"` -} - -// Used to generate rtypes like MX rand SRV ecords, which have multiple -// fields within the rtype. -type complexFields struct { - TTL uint32 `yaml:"ttl,omitempty"` - Type string `yaml:"type"` - Fields []fields `yaml:"values,omitempty"` -} - -// Used to generate the fields themselves: -type fields struct { - Priority uint16 `yaml:"priority,omitempty"` - SrvWeight uint16 `yaml:"weight,omitempty"` - SrvPort uint16 `yaml:"port,omitempty"` - Value string `yaml:"value,omitempty"` -} - -// FIXME(tlim): An MX record with .Priority=0 will not output the priority. - -// sameType returns true if all records have the same type. -func sameType(records models.Records) bool { - t := records[0].Type - for _, r := range records { - if r.Type != t { - return false - } - } - return true -} - -// oneLabel handles all the DNS records associated with a single label. -// It dispatches the right code whether the label is simple, many, or complex. -func oneLabel(records models.Records) yaml.MapItem { - item := yaml.MapItem{ - // a yaml.MapItem is a YAML map that retains the key order. - Key: records[0].GetLabel(), - } - // Special case labels with a single record: - if len(records) == 1 { - switch rtype := records[0].Type; rtype { - case "A", "CNAME", "NS", "PTR", "TXT": - v := simple{ - Type: rtype, - Value: records[0].GetTargetField(), - TTL: records[0].TTL, - } - if v.Type == "TXT" { - v.Value = strings.Replace(models.StripQuotes(v.Value), `;`, `\;`, -1) - } - //printer.Printf("yamlwrite:oneLabel: simple ttl=%d\n", v.TTL) - item.Value = v - //printer.Printf("yamlwrite:oneLabel: SIMPLE=%v\n", item) - return item - case "MX", "SRV": - // Always processed as a complex{} - default: - panic(fmt.Errorf("yamlwrite:oneLabel:len1 rtype not implemented: %s", rtype)) - } - } - - // Special case labels with many records, all the same rType: - if sameType(records) { - switch rtype := records[0].Type; rtype { - case "A", "CNAME", "NS": - v := many{ - Type: rtype, - TTL: records[0].TTL, - } - for _, rec := range records { - v.Values = append(v.Values, rec.GetTargetField()) - } - item.Value = v - //printer.Printf("SIMPLE=%v\n", item) - return item - case "MX", "SRV": - // Always processed as a complex{} - default: - panic(fmt.Errorf("oneLabel:many rtype not implemented: %s", rtype)) - } - } - - // All other labels are complexItems - - var low int // First index of a run. - var lst complexItems - var last = records[0].Type - for i := range records { - if records[i].Type != last { - //printer.Printf("yamlwrite:oneLabel: Calling oneType( [%d:%d] ) last=%s type=%s\n", low, i, last, records[0].Type) - lst = append(lst, oneType(records[low:i])) - low = i // Current is the first of a run. - last = records[i].Type - } - if i == (len(records) - 1) { - // we are on the last element. - //printer.Printf("yamlwrite:oneLabel: Calling oneType( [%d:%d] ) last=%s type=%s\n", low, i+1, last, records[0].Type) - lst = append(lst, oneType(records[low:i+1])) - } - } - item.Value = lst - - return item -} - -// oneType returns interfaces that will MarshalYAML properly for a label with -// one or more records, all the same rtype. -func oneType(records models.Records) interface{} { - //printer.Printf("yamlwrite:oneType len=%d type=%s\n", len(records), records[0].Type) - rtype := records[0].Type - switch rtype { - case "A", "AAAA", "NS": - vv := complexVals{ - Type: rtype, - TTL: records[0].TTL, - } - if len(records) == 1 { - vv.Value = records[0].GetTargetField() - } else { - for _, rc := range records { - vv.Values = append(vv.Values, rc.GetTargetCombined()) - } - } - return vv - case "MX": - vv := complexFields{ - Type: rtype, - TTL: records[0].TTL, - } - for _, rc := range records { - vv.Fields = append(vv.Fields, fields{ - Value: rc.GetTargetField(), - Priority: rc.MxPreference, - }) - } - return vv - case "SRV": - vv := complexFields{ - Type: rtype, - TTL: records[0].TTL, - } - for _, rc := range records { - vv.Fields = append(vv.Fields, fields{ - Value: rc.GetTargetField(), - Priority: rc.SrvPriority, - SrvWeight: rc.SrvWeight, - SrvPort: rc.SrvPort, - }) - } - return vv - case "TXT": - vv := complexVals{ - Type: rtype, - TTL: records[0].TTL, - } - if len(records) == 1 { - vv.Value = strings.Replace(models.StripQuotes(records[0].GetTargetField()), `;`, `\;`, -1) - } else { - for _, rc := range records { - vv.Values = append(vv.Values, models.StripQuotes(rc.GetTargetCombined())) - } - } - return vv - - default: - panic(fmt.Errorf("yamlwrite:oneType rtype=%s not implemented", rtype)) - } -} - -// mostCommonTTL returns the most common TTL in a set of records. If there is -// a tie, the highest TTL is selected. This makes the results consistent. -// NS records are not included in the analysis because Tom said so. -func mostCommonTTL(records models.Records) uint32 { - // Index the TTLs in use: - d := make(map[uint32]int) - for _, r := range records { - if r.Type != "NS" { - d[r.TTL]++ - } - } - // Find the largest count: - var mc int - for _, value := range d { - if value > mc { - mc = value - } - } - // Find the largest key with that count: - var mk uint32 - for key, value := range d { - if value == mc { - if key > mk { - mk = key - } - } - } - return mk -} diff --git a/providers/octodns/staticcheck.conf b/providers/octodns/staticcheck.conf deleted file mode 100644 index f147677e5..000000000 --- a/providers/octodns/staticcheck.conf +++ /dev/null @@ -1 +0,0 @@ -checks = ["inherit", "-S1034"] diff --git a/providers/octodns/testdata/production.yaml b/providers/octodns/testdata/production.yaml deleted file mode 100644 index 689b7662a..000000000 --- a/providers/octodns/testdata/production.yaml +++ /dev/null @@ -1,84 +0,0 @@ ---- -providers: - config: - class: octodns.provider.yaml.YamlProvider - directory: ./config -zones: - apptivate.ms.: - sources: - - config - askubuntu.com.: - sources: - - config - blogoverflow.com.: - sources: - - config - bosun.org.: - sources: - - config - hashcode.ru.: - sources: - - config - isstackoverflowdownforeveryoneorjustme.com.: - sources: - - config - mathoverflow.net.: - sources: - - config - miniprofiler.com.: - sources: - - config - s.tk.: - sources: - - config - serverfault.com.: - sources: - - config - sezn.ru.: - sources: - - config - sstatic.net.: - sources: - - config - stackapps.com.: - sources: - - config - stackauth.com.: - sources: - - config - stackenterprise.co.: - sources: - - config - stackex.com.: - sources: - - config - stackexchange.com.: - sources: - - config - stackoverflow.blog.: - sources: - - config - stackoverflow.com.: - sources: - - config - stackoverflow.design.: - sources: - - config - stackoverflow.email.: - sources: - - config - stackoverflow.ru.: - sources: - - config - stackoverflowbusiness.com.: - sources: - - config - stacksnippets.net.: - sources: - - config - superuser.com.: - sources: - - config - teststackoverflow.com.: - sources: - - config