Refactor in preparation to unexport RecordConfig.{Name,NameFQDN,Target} ()

* Preparing for the unexport of Name/NameFQDN/Target
* Cleanups
This commit is contained in:
Tom Limoncelli 2018-03-19 17:18:58 -04:00 committed by GitHub
parent cd58d26545
commit a7eba97ada
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 298 additions and 270 deletions

View file

@ -107,9 +107,11 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
dom, _ := dc.Copy()
for _, r := range tst.Records {
rc := models.RecordConfig(*r)
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, domainName)
if strings.Contains(rc.Target, "**current-domain**") {
rc.Target = strings.Replace(rc.Target, "**current-domain**", domainName, 1) + "."
if strings.Contains(rc.GetTargetField(), "**current-domain**") {
rc.SetTarget(strings.Replace(rc.GetTargetField(), "**current-domain**", domainName, 1) + ".")
}
if strings.Contains(rc.GetLabelFQDN(), "**current-domain**") {
rc.SetLabelFromFQDN(strings.Replace(rc.GetLabelFQDN(), "**current-domain**", domainName, 1), domainName)
}
dom.Records = append(dom.Records, &rc)
}
@ -205,6 +207,19 @@ type TestCase struct {
type rec models.RecordConfig
func (r *rec) GetLabel() string {
return r.Name
}
func (r *rec) SetLabel(label, domain string) {
r.Name = label
r.NameFQDN = dnsutil.AddOrigin(label, "**current-domain**")
}
func (r *rec) SetTarget(target string) {
r.Target = target
}
func a(name, target string) *rec {
return makeRec(name, target, "A")
}
@ -273,24 +288,25 @@ func tlsa(name string, usage, selector, matchingtype uint8, target string) *rec
r.TlsaUsage = usage
r.TlsaSelector = selector
r.TlsaMatchingType = matchingtype
r.Target = target
return r
}
func ignore(name string) *rec {
return &rec{
Name: name,
r := &rec{
Type: "IGNORE",
}
r.SetLabel(name, "**current-domain**")
return r
}
func makeRec(name, target, typ string) *rec {
return &rec{
Name: name,
Type: typ,
Target: target,
TTL: 300,
r := &rec{
Type: typ,
TTL: 300,
}
r.SetLabel(name, "**current-domain**")
r.SetTarget(target)
return r
}
func (r *rec) ttl(t uint32) *rec {
@ -303,7 +319,7 @@ func tc(desc string, recs ...*rec) *TestCase {
var ignored []string
for _, r := range recs {
if r.Type == "IGNORE" {
ignored = append(ignored, r.Name)
ignored = append(ignored, r.GetLabel())
} else {
records = append(records, r)
}

View file

@ -26,9 +26,9 @@ func TestRR(t *testing.T) {
experiment := RecordConfig{
Type: "A",
Name: "foo",
NameFQDN: "foo.example.com",
Target: "1.2.3.4",
TTL: 0,
NameFQDN: "foo.example.com",
MxPreference: 0,
}
expected := "foo.example.com.\t300\tIN\tA\t1.2.3.4"
@ -40,9 +40,9 @@ func TestRR(t *testing.T) {
experiment = RecordConfig{
Type: "CAA",
Name: "@",
NameFQDN: "example.com",
Target: "mailto:test@example.com",
TTL: 300,
NameFQDN: "example.com",
CaaTag: "iodef",
CaaFlag: 1,
}
@ -55,9 +55,9 @@ func TestRR(t *testing.T) {
experiment = RecordConfig{
Type: "TLSA",
Name: "@",
NameFQDN: "_443._tcp.example.com",
Target: "abcdef0123456789",
TTL: 300,
NameFQDN: "_443._tcp.example.com",
TlsaUsage: 0,
TlsaSelector: 0,
TlsaMatchingType: 1,
@ -74,17 +74,17 @@ func TestDowncase(t *testing.T) {
&RecordConfig{Type: "MX", Name: "lower", Target: "targetmx"},
&RecordConfig{Type: "MX", Name: "UPPER", Target: "TARGETMX"},
}}
Downcase(dc.Records)
downcase(dc.Records)
if !dc.HasRecordTypeName("MX", "lower") {
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
}
if !dc.HasRecordTypeName("MX", "upper") {
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
}
if dc.Records[0].Target != "targetmx" {
t.Errorf("%v: target0 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[0].Target)
if dc.Records[0].GetTargetField() != "targetmx" {
t.Errorf("%v: target0 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[0].GetTargetField())
}
if dc.Records[1].Target != "targetmx" {
t.Errorf("%v: target1 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[1].Target)
if dc.Records[1].GetTargetField() != "targetmx" {
t.Errorf("%v: target1 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[1].GetTargetField())
}
}

View file

@ -49,7 +49,7 @@ func (dc *DomainConfig) Copy() (*DomainConfig, error) {
// HasRecordTypeName returns True if there is a record with this rtype and name.
func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool {
for _, r := range dc.Records {
if r.Type == rtype && r.Name == name {
if r.Type == rtype && r.GetLabel() == name {
return true
}
}
@ -73,19 +73,17 @@ func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) {
// - NameFQDN
// - Target (CNAME and MX only)
func (dc *DomainConfig) Punycode() error {
var err error
for _, rec := range dc.Records {
rec.Name, err = idna.ToASCII(rec.Name)
if err != nil {
return err
}
rec.NameFQDN, err = idna.ToASCII(rec.NameFQDN)
t, err := idna.ToASCII(rec.GetLabelFQDN())
if err != nil {
return err
}
rec.SetLabelFromFQDN(t, dc.Name)
switch rec.Type { // #rtype_variations
case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS":
rec.Target, err = idna.ToASCII(rec.Target)
// These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record)
t, err := idna.ToASCII(rec.GetTargetField())
rec.SetTarget(t)
if err != nil {
return err
}

View file

@ -120,6 +120,14 @@ func (rc *RecordConfig) SetLabel(short, origin string) {
}
}
// UnsafeSetLabelNull sets the label to "". Normally the FQDN is denoted by .Name being
// "@" however this can be used to violate that assertion. It should only be used
// on copies of a RecordConfig that is being used for non-standard things like
// Marshalling yaml.
func (rc *RecordConfig) UnsafeSetLabelNull() {
rc.Name = ""
}
// SetLabelFromFQDN sets the .Name/.NameFQDN fields given a FQDN and origin.
// fqdn may have a trailing "." but it is not required.
// origin may not have a trailing dot.
@ -268,11 +276,11 @@ func (r Records) GroupedByLabel() ([]string, map[string]Records) {
// PostProcessRecords does any post-processing of the downloaded DNS records.
func PostProcessRecords(recs []*RecordConfig) {
Downcase(recs)
downcase(recs)
}
// Downcase converts all labels and targets to lowercase in a list of RecordConfig.
func Downcase(recs []*RecordConfig) {
func downcase(recs []*RecordConfig) {
for _, r := range recs {
r.Name = strings.ToLower(r.Name)
r.NameFQDN = strings.ToLower(r.NameFQDN)

View file

@ -11,7 +11,7 @@ import (
func (rc *RecordConfig) SetTargetCAA(flag uint8, tag string, target string) error {
rc.CaaTag = tag
rc.CaaFlag = flag
rc.Target = target
rc.SetTarget(target)
if rc.Type == "" {
rc.Type = "CAA"
}

View file

@ -10,7 +10,7 @@ import (
// SetTargetMX sets the MX fields.
func (rc *RecordConfig) SetTargetMX(pref uint16, target string) error {
rc.MxPreference = pref
rc.Target = target
rc.SetTarget(target)
if rc.Type == "" {
rc.Type = "MX"
}

View file

@ -12,7 +12,7 @@ func (rc *RecordConfig) SetTargetSRV(priority, weight, port uint16, target strin
rc.SrvPriority = priority
rc.SrvWeight = weight
rc.SrvPort = port
rc.Target = target
rc.SetTarget(target)
if rc.Type == "" {
rc.Type = "SRV"
}

View file

@ -12,7 +12,7 @@ func (rc *RecordConfig) SetTargetTLSA(usage, selector, matchingtype uint8, targe
rc.TlsaUsage = usage
rc.TlsaSelector = selector
rc.TlsaMatchingType = matchingtype
rc.Target = target
rc.SetTarget(target)
if rc.Type == "" {
rc.Type = "TLSA"
}

View file

@ -2,7 +2,7 @@ package models
// SetTargetTXT sets the TXT fields when there is 1 string.
func (rc *RecordConfig) SetTargetTXT(s string) error {
rc.Target = s
rc.SetTarget(s)
rc.TxtStrings = []string{s}
if rc.Type == "" {
rc.Type = "TXT"
@ -15,7 +15,7 @@ func (rc *RecordConfig) SetTargetTXT(s string) error {
// SetTargetTXTs sets the TXT fields when there are many strings.
func (rc *RecordConfig) SetTargetTXTs(s []string) error {
rc.Target = s[0]
rc.SetTarget(s[0])
rc.TxtStrings = s
if rc.Type == "" {
rc.Type = "TXT"

View file

@ -109,11 +109,11 @@ func (rc *RecordConfig) SetTarget(target string) error {
// SetTargetIP sets the target to an IP, verifying this is an appropriate rtype.
func (rc *RecordConfig) SetTargetIP(ip net.IP) error {
// TODO(tlim): Verify the rtype is appropriate for an IP.
rc.Target = ip.String()
rc.SetTarget(ip.String())
return nil
}
// // SetTargetFQDN sets the target to an IP, verifying this is an appropriate rtype.
// // SetTargetFQDN sets the target to a string, verifying this is an appropriate rtype.
// func (rc *RecordConfig) SetTargetFQDN(target string) error {
// // TODO(tlim): Verify the rtype is appropriate for an hostname.
// rc.Target = target

View file

@ -8,7 +8,6 @@ import (
"strconv"
"github.com/StackExchange/dnscontrol/models"
"github.com/miekg/dns/dnsutil"
)
// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules:
@ -52,15 +51,16 @@ func AddNSRecords(dc *models.DomainConfig) {
for _, ns := range dc.Nameservers {
rc := &models.RecordConfig{
Type: "NS",
Name: "@",
Target: ns.Name,
Metadata: map[string]string{},
TTL: ttl,
}
if !strings.HasSuffix(rc.Target, ".") {
rc.Target += "."
rc.SetLabel("@", dc.Name)
t := ns.Name
if !strings.HasSuffix(t, ".") {
rc.SetTarget(t + ".")
}
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, dc.Name)
rc.SetTarget(t)
dc.Records = append(dc.Records, rc)
}
}

View file

@ -3,7 +3,6 @@ package normalize
import (
"strings"
"github.com/miekg/dns/dnsutil"
"github.com/pkg/errors"
"github.com/StackExchange/dnscontrol/models"
@ -27,13 +26,13 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
return []error{err}
}
}
rec, err = spflib.Parse(txt.Target, cache)
rec, err = spflib.Parse(txt.GetTargetField(), cache)
if err != nil {
errs = append(errs, err)
continue
}
}
if flatten, ok := txt.Metadata["flatten"]; ok && strings.HasPrefix(txt.Target, "v=spf1") {
if flatten, ok := txt.Metadata["flatten"]; ok && strings.HasPrefix(txt.GetTargetField(), "v=spf1") {
rec = rec.Flatten(flatten)
err = txt.SetTargetTXT(rec.TXT())
if err != nil {
@ -44,7 +43,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
// now split if needed
if split, ok := txt.Metadata["split"]; ok {
if !strings.Contains(split, "%d") {
errs = append(errs, Warning{errors.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.NameFQDN)})
errs = append(errs, Warning{errors.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.GetLabelFQDN())})
continue
}
recs := rec.TXTSplit(split + "." + domain.Name)
@ -54,8 +53,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
} else {
cp, _ := txt.Copy()
cp.SetTargetTXT(v)
cp.NameFQDN = k
cp.Name = dnsutil.TrimDomainName(k, domain.Name)
cp.SetLabelFromFQDN(k, domain.Name)
domain.Records = append(domain.Records, cp)
}
}

View file

@ -6,6 +6,12 @@ import (
"github.com/StackExchange/dnscontrol/models"
)
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
rc.SetLabel(label, domain)
rc.SetTarget(target)
return &rc
}
func TestImportTransform(t *testing.T) {
const transformDouble = "0.0.0.0~1.1.1.1~~9.0.0.0,10.0.0.0"
@ -13,15 +19,15 @@ func TestImportTransform(t *testing.T) {
src := &models.DomainConfig{
Name: "stackexchange.com",
Records: []*models.RecordConfig{
{Type: "A", Name: "*", NameFQDN: "*.stackexchange.com", Target: "0.0.2.2"},
{Type: "A", Name: "www", NameFQDN: "www.stackexchange.com", Target: "0.0.1.1"},
makeRC("*", "stackexchange.com", "0.0.2.2", models.RecordConfig{Type: "A"}),
makeRC("www", "stackexchange.com", "0.0.1.1", models.RecordConfig{Type: "A"}),
},
}
dst := &models.DomainConfig{
Name: "internal",
Records: []*models.RecordConfig{
{Type: "A", Name: "*.stackexchange.com", NameFQDN: "*.stackexchange.com.internal", Target: "0.0.3.3", Metadata: map[string]string{"transform_table": transformSingle}},
{Type: "IMPORT_TRANSFORM", Name: "@", NameFQDN: "internal", Target: "stackexchange.com", Metadata: map[string]string{"transform_table": transformDouble}},
makeRC("*.stackexchange.com", "*.stackexchange.com.internal", "0.0.3.3", models.RecordConfig{Type: "A", Metadata: map[string]string{"transform_table": transformSingle}}),
makeRC("@", "internal", "stackexchange.com", models.RecordConfig{Type: "IMPORT_TRANSFORM", Metadata: map[string]string{"transform_table": transformDouble}}),
},
}
cfg := &models.DNSConfig{

View file

@ -66,7 +66,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
if !ok {
cType := providers.GetCustomRecordType(rec.Type)
if cType == nil {
return errors.Errorf("Unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.Name)
return errors.Errorf("Unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel())
}
for _, providerType := range pTypes {
if providerType != cType.Provider {
@ -125,11 +125,11 @@ func checkLabel(label string, rType string, domain string, meta map[string]strin
// checkTargets returns true if rec.Target is valid for the rec.Type.
func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
label := rec.Name
target := rec.Target
label := rec.GetLabel()
target := rec.GetTargetField()
check := func(e error) {
if e != nil {
err := errors.Errorf("In %s %s.%s: %s", rec.Type, rec.Name, domain, e.Error())
err := errors.Errorf("In %s %s.%s: %s", rec.Type, rec.GetLabel(), domain, e.Error())
if _, ok := e.(Warning); ok {
err = Warning{err}
}
@ -166,7 +166,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
return
}
errs = append(errs, errors.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v",
rec.Type, domain, rec.Name))
rec.Type, domain, rec.GetLabel()))
}
return
}
@ -189,13 +189,13 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra
// 4. For As, change the target as described the transforms.
for _, rec := range srcDomain.Records {
if dstDomain.HasRecordTypeName(rec.Type, rec.NameFQDN) {
if dstDomain.HasRecordTypeName(rec.Type, rec.GetLabelFQDN()) {
continue
}
newRec := func() *models.RecordConfig {
rec2, _ := rec.Copy()
rec2.Name = rec2.NameFQDN
rec2.NameFQDN = dnsutil.AddOrigin(rec2.Name, dstDomain.Name)
newlabel := rec2.GetLabelFQDN()
rec2.SetLabelFromFQDN(newlabel, dstDomain.Name)
if ttl != 0 {
rec2.TTL = ttl
}
@ -203,25 +203,25 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra
}
switch rec.Type { // #rtype_variations
case "A":
trs, err := transform.TransformIPToList(net.ParseIP(rec.Target), transforms)
trs, err := transform.TransformIPToList(net.ParseIP(rec.GetTargetField()), transforms)
if err != nil {
return errors.Errorf("import_transform: TransformIP(%v, %v) returned err=%s", rec.Target, transforms, err)
return errors.Errorf("import_transform: TransformIP(%v, %v) returned err=%s", rec.GetTargetField(), transforms, err)
}
for _, tr := range trs {
r := newRec()
r.Target = tr.String()
r.SetTarget(tr.String())
dstDomain.Records = append(dstDomain.Records, r)
}
case "CNAME":
r := newRec()
r.Target = transformCNAME(r.Target, srcDomain.Name, dstDomain.Name)
r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name))
dstDomain.Records = append(dstDomain.Records, r)
case "MX", "NS", "SRV", "TXT", "CAA", "TLSA":
// Not imported.
continue
default:
return errors.Errorf("import_transform: Unimplemented record type %v (%v)",
rec.Type, rec.Name)
rec.Type, rec.GetLabel())
}
}
return nil
@ -276,7 +276,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
if err := validateRecordTypes(rec, domain.Name, pTypes); err != nil {
errs = append(errs, err)
}
if err := checkLabel(rec.Name, rec.Type, domain.Name, rec.Metadata); err != nil {
if err := checkLabel(rec.GetLabel(), rec.Type, domain.Name, rec.Metadata); err != nil {
errs = append(errs, err)
}
if errs2 := checkTargets(rec, domain.Name); errs2 != nil {
@ -285,14 +285,16 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
// Canonicalize Targets.
if rec.Type == "CNAME" || rec.Type == "MX" || rec.Type == "NS" {
rec.Target = dnsutil.AddOrigin(rec.Target, domain.Name+".")
rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), domain.Name+"."))
} else if rec.Type == "A" || rec.Type == "AAAA" {
rec.Target = net.ParseIP(rec.Target).String()
rec.SetTarget(net.ParseIP(rec.GetTargetField()).String())
} else if rec.Type == "PTR" {
var err error
if rec.Name, err = transform.PtrNameMagic(rec.Name, domain.Name); err != nil {
var name string
if name, err = transform.PtrNameMagic(rec.GetLabel(), domain.Name); err != nil {
errs = append(errs, err)
}
rec.SetLabel(name, domain.Name)
} else if rec.Type == "CAA" {
if rec.CaaTag != "issue" && rec.CaaTag != "issuewild" && rec.CaaTag != "iodef" {
errs = append(errs, errors.Errorf("CAA tag %s is invalid", rec.CaaTag))
@ -300,26 +302,26 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
} else if rec.Type == "TLSA" {
if rec.TlsaUsage < 0 || rec.TlsaUsage > 3 {
errs = append(errs, errors.Errorf("TLSA Usage %d is invalid in record %s (domain %s)",
rec.TlsaUsage, rec.Name, domain.Name))
rec.TlsaUsage, rec.GetLabel(), domain.Name))
}
if rec.TlsaSelector < 0 || rec.TlsaSelector > 1 {
errs = append(errs, errors.Errorf("TLSA Selector %d is invalid in record %s (domain %s)",
rec.TlsaSelector, rec.Name, domain.Name))
rec.TlsaSelector, rec.GetLabel(), domain.Name))
}
if rec.TlsaMatchingType < 0 || rec.TlsaMatchingType > 2 {
errs = append(errs, errors.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)",
rec.TlsaMatchingType, rec.Name, domain.Name))
rec.TlsaMatchingType, rec.GetLabel(), domain.Name))
}
} else if rec.Type == "TXT" && len(txtMultiDissenters) != 0 && len(rec.TxtStrings) > 1 {
// There are providers that don't support TXTMulti yet there is
// a TXT record with multiple strings:
errs = append(errs,
errors.Errorf("TXT records with multiple strings (label %v domain: %v) not supported by %s",
rec.Name, domain.Name, strings.Join(txtMultiDissenters, ",")))
rec.GetLabel(), domain.Name, strings.Join(txtMultiDissenters, ",")))
}
// Populate FQDN:
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
//rec.NameFQDN = dnsutil.AddOrigin(rec.GetLabel(), domain.Name)
}
}
@ -337,7 +339,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
errs = append(errs, err)
continue
}
err = importTransform(config.FindDomain(rec.Target), domain, table, rec.TTL)
err = importTransform(config.FindDomain(rec.GetTargetField()), domain, table, rec.TTL)
if err != nil {
errs = append(errs, err)
}
@ -375,15 +377,15 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) {
cnames := map[string]bool{}
for _, r := range dc.Records {
if r.Type == "CNAME" {
if cnames[r.Name] {
errs = append(errs, errors.Errorf("Cannot have multiple CNAMEs with same name: %s", r.NameFQDN))
if cnames[r.GetLabel()] {
errs = append(errs, errors.Errorf("Cannot have multiple CNAMEs with same name: %s", r.GetLabelFQDN()))
}
cnames[r.Name] = true
cnames[r.GetLabel()] = true
}
}
for _, r := range dc.Records {
if cnames[r.Name] && r.Type != "CNAME" {
errs = append(errs, errors.Errorf("Cannot have CNAME and %s record with same name: %s", r.Type, r.NameFQDN))
if cnames[r.GetLabel()] && r.Type != "CNAME" {
errs = append(errs, errors.Errorf("Cannot have CNAME and %s record with same name: %s", r.Type, r.GetLabelFQDN()))
}
}
return
@ -433,21 +435,21 @@ func applyRecordTransforms(domain *models.DomainConfig) error {
if err != nil {
return err
}
ip := net.ParseIP(rec.Target) // ip already validated above
newIPs, err := transform.TransformIPToList(net.ParseIP(rec.Target), table)
ip := net.ParseIP(rec.GetTargetField()) // ip already validated above
newIPs, err := transform.TransformIPToList(net.ParseIP(rec.GetTargetField()), table)
if err != nil {
return err
}
for i, newIP := range newIPs {
if i == 0 && !newIP.Equal(ip) {
rec.Target = newIP.String() // replace target of first record if different
rec.SetTarget(newIP.String()) // replace target of first record if different
} else if i > 0 {
// any additional ips need identical records with the alternate ip added to the domain
copy, err := rec.Copy()
if err != nil {
return err
}
copy.Target = newIP.String()
copy.SetTarget(newIP.String())
domain.Records = append(domain.Records, copy)
}
}

View file

@ -113,12 +113,14 @@ func Test_transform_cname(t *testing.T) {
func TestNSAtRoot(t *testing.T) {
// do not allow ns records for @
rec := &models.RecordConfig{Name: "test", Type: "NS", Target: "ns1.name.com."}
rec := &models.RecordConfig{Type: "NS"}
rec.SetLabel("test", "foo.com")
rec.SetTarget("ns1.name.com.")
errs := checkTargets(rec, "foo.com")
if len(errs) > 0 {
t.Error("Expect no error with ns record on subdomain")
}
rec.Name = "@"
rec.SetLabel("@", "foo.com")
errs = checkTargets(rec, "foo.com")
if len(errs) != 1 {
t.Error("Expect error with ns record on @")
@ -138,7 +140,7 @@ func TestTransforms(t *testing.T) {
for i, test := range tests {
dc := &models.DomainConfig{
Records: []*models.RecordConfig{
{Type: "A", Target: test.givenIP, Metadata: map[string]string{"transform": transform}},
makeRC("f", "example.tld", test.givenIP, models.RecordConfig{Type: "A", Metadata: map[string]string{"transform": transform}}),
},
}
err := applyRecordTransforms(dc)
@ -151,8 +153,8 @@ func TestTransforms(t *testing.T) {
continue
}
for r, rec := range dc.Records {
if rec.Target != test.expectedRecords[r] {
t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], rec.Target)
if rec.GetTargetField() != test.expectedRecords[r] {
t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], rec.GetTargetField())
continue
}
}
@ -160,7 +162,9 @@ func TestTransforms(t *testing.T) {
}
func TestCNAMEMutex(t *testing.T) {
var recA = &models.RecordConfig{Type: "CNAME", Name: "foo", NameFQDN: "foo.example.com", Target: "example.com."}
var recA = &models.RecordConfig{Type: "CNAME"}
recA.SetLabel("foo", "foo.example.com")
recA.SetTarget("example.com.")
tests := []struct {
rType string
name string
@ -173,7 +177,9 @@ func TestCNAMEMutex(t *testing.T) {
}
for _, tst := range tests {
t.Run(fmt.Sprintf("%s %s", tst.rType, tst.name), func(t *testing.T) {
var recB = &models.RecordConfig{Type: tst.rType, Name: tst.name, NameFQDN: tst.name + ".example.com", Target: "example2.com."}
var recB = &models.RecordConfig{Type: tst.rType}
recB.SetLabel(tst.name, "example.com")
recB.SetTarget("example2.com.")
dc := &models.DomainConfig{
Name: "example.com",
Records: []*models.RecordConfig{recA, recB},
@ -196,7 +202,7 @@ func TestCAAValidation(t *testing.T) {
Name: "example.com",
RegistrarName: "BIND",
Records: []*models.RecordConfig{
{Name: "@", NameFQDN: "example.com", Type: "CAA", CaaTag: "invalid", Target: "example.com"},
makeRC("@", "example.com", "example.com", models.RecordConfig{Type: "CAA", CaaTag: "invalid"}),
},
},
},
@ -214,7 +220,8 @@ func TestTLSAValidation(t *testing.T) {
Name: "_443._tcp.example.com",
RegistrarName: "BIND",
Records: []*models.RecordConfig{
{Name: "_443._tcp", NameFQDN: "_443._tcp._443._tcp.example.com", Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, Target: "abcdef0"},
makeRC("_443._tcp", "_443._tcp.example.com", "abcdef0", models.RecordConfig{
Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1}),
},
},
},

View file

@ -11,7 +11,6 @@ import (
"github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers/diff"
"github.com/TomOnTime/utfutil"
"github.com/miekg/dns/dnsutil"
"github.com/pkg/errors"
)
@ -35,7 +34,7 @@ func (c *adProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Co
dc.Filter(func(r *models.RecordConfig) bool {
if r.Type != "A" && r.Type != "CNAME" {
log.Printf("WARNING: Active Directory only manages A and CNAME records. Won't consider %s %s", r.Type, r.NameFQDN)
log.Printf("WARNING: Active Directory only manages A and CNAME records. Won't consider %s %s", r.Type, r.GetLabelFQDN())
return false
}
return true
@ -162,18 +161,16 @@ func (c *adProvider) getExistingRecords(domainname string) ([]*models.RecordConf
}
func (r *RecordConfigJson) unpackRecord(origin string) *models.RecordConfig {
rc := models.RecordConfig{}
rc.Name = strings.ToLower(r.Name)
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, origin)
rc.Type = r.Type
rc.TTL = r.TTL
switch rc.Type { // #rtype_variations
case "A":
rc.Target = r.Data
rc := models.RecordConfig{
Type: r.Type,
TTL: r.TTL,
}
rc.SetLabel(r.Name, origin)
switch rtype := rc.Type; rtype { // #rtype_variations
case "A", "AAAA":
rc.SetTarget(r.Data)
case "CNAME":
rc.Target = strings.ToLower(r.Data)
rc.SetTarget(strings.ToLower(r.Data))
case "NS", "SOA":
return nil
default:
@ -197,12 +194,12 @@ Get-DnsServerResourceRecord -ComputerName REPLACE_WITH_COMPUTER_NAME -ZoneName $
// generatePowerShellCreate generates PowerShell commands to ADD a record.
func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.RecordConfig) string {
content := rec.Target
content := rec.GetTargetField()
text := "\r\n" // Skip a line.
text += fmt.Sprintf("Add-DnsServerResourceRecord%s", rec.Type)
text += fmt.Sprintf(` -ComputerName "%s"`, c.adServer)
text += fmt.Sprintf(` -ZoneName "%s"`, domainname)
text += fmt.Sprintf(` -Name "%s"`, rec.Name)
text += fmt.Sprintf(` -Name "%s"`, rec.GetLabel())
text += fmt.Sprintf(` -TimeToLive $(New-TimeSpan -Seconds %d)`, rec.TTL)
switch rec.Type { // #rtype_variations
case "CNAME":
@ -210,9 +207,10 @@ func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.Rec
case "A":
text += fmt.Sprintf(` -IPv4Address "%s"`, content)
case "NS":
text = fmt.Sprintf("\r\n"+`echo "Skipping NS update (%v %v)"`+"\r\n", rec.Name, rec.Target)
text = fmt.Sprintf("\r\n"+`echo "Skipping NS update (%v %v)"`+"\r\n", rec.GetLabel(), rec.GetTargetDebug())
default:
panic(errors.Errorf("generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)", rec.Type, rec.Name, content))
panic(errors.Errorf("generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)",
rec.Type, rec.GetLabel(), content))
// We panic so that we quickly find any switch statements
// that have not been updated for a new RR type.
}
@ -286,7 +284,7 @@ func (c *adProvider) generatePowerShellDelete(domainname, recName, recType, cont
func (c *adProvider) createRec(domainname string, rec *models.RecordConfig) []*models.Correction {
arr := []*models.Correction{
{
Msg: fmt.Sprintf("CREATE record: %s %s ttl(%d) %s", rec.Name, rec.Type, rec.TTL, rec.Target),
Msg: fmt.Sprintf("CREATE record: %s %s ttl(%d) %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField()),
F: func() error {
return c.powerShellDoCommand(c.generatePowerShellCreate(domainname, rec), true)
}},
@ -299,16 +297,16 @@ func (c *adProvider) modifyRec(domainname string, m diff.Correlation) *models.Co
return &models.Correction{
Msg: m.String(),
F: func() error {
return c.powerShellDoCommand(c.generatePowerShellModify(domainname, rec.Name, rec.Type, old.Target, rec.Target, old.TTL, rec.TTL), true)
return c.powerShellDoCommand(c.generatePowerShellModify(domainname, rec.GetLabel(), rec.Type, old.GetTargetField(), rec.GetTargetField(), old.TTL, rec.TTL), true)
},
}
}
func (c *adProvider) deleteRec(domainname string, rec *models.RecordConfig) *models.Correction {
return &models.Correction{
Msg: fmt.Sprintf("DELETE record: %s %s ttl(%d) %s", rec.Name, rec.Type, rec.TTL, rec.Target),
Msg: fmt.Sprintf("DELETE record: %s %s ttl(%d) %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField()),
F: func() error {
return c.powerShellDoCommand(c.generatePowerShellDelete(domainname, rec.Name, rec.Type, rec.Target), true)
return c.powerShellDoCommand(c.generatePowerShellDelete(domainname, rec.GetLabel(), rec.Type, rec.GetTargetField()), true)
},
}
}

View file

@ -7,6 +7,12 @@ import (
"github.com/StackExchange/dnscontrol/models"
)
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
rc.SetLabel(label, domain)
rc.SetTarget(target)
return &rc
}
func TestGetExistingRecords(t *testing.T) {
cf := &adProvider{}
@ -17,11 +23,11 @@ func TestGetExistingRecords(t *testing.T) {
t.Fatal(err)
}
expected := []*models.RecordConfig{
{Name: "@", NameFQDN: "test2", Type: "A", TTL: 600, Target: "10.166.2.11"},
//{Name: "_msdcs", NameFQDN: "_msdcs.test2", Type: "NS", TTL: 300, Target: "other_record"}, // Will be filtered.
{Name: "co-devsearch02", NameFQDN: "co-devsearch02.test2", Type: "A", TTL: 3600, Target: "10.8.2.64"},
{Name: "co-devservice01", NameFQDN: "co-devservice01.test2", Type: "A", TTL: 1200, Target: "10.8.2.48"}, // Downcased.
{Name: "yum", NameFQDN: "yum.test2", Type: "A", TTL: 3600, Target: "10.8.0.59"},
makeRC("@", "test2", "10.166.2.11", models.RecordConfig{Type: "A", TTL: 600}),
//makeRC("_msdcs", "test2", "other_record", models.RecordConfig{Type: "NS", TTL: 300}), // Will be filtered.
makeRC("co-devsearch02", "test2", "10.8.2.64", models.RecordConfig{Type: "A", TTL: 3600}),
makeRC("co-devservice01", "test2", "10.8.2.48", models.RecordConfig{Type: "A", TTL: 1200}), // Downcased.
makeRC("yum", "test2", "10.8.0.59", models.RecordConfig{Type: "A", TTL: 3600}),
}
actualS := ""

View file

@ -127,7 +127,7 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
}
newSerial = v.Serial
//if (dnsutil.TrimDomainName(rc.Name, origin+".") == "@") && replaceSerial != 0 {
if rc.Name == "@" && replaceSerial != 0 {
if rc.GetLabel() == "@" && replaceSerial != 0 {
newSerial = replaceSerial
}
panicInvalid(rc.SetTarget(

View file

@ -16,14 +16,25 @@ func newDomainConfig() *models.DomainConfig {
}
}
func makeRCmeta(meta map[string]string) *models.RecordConfig {
rc := models.RecordConfig{
Type: "A",
Metadata: meta,
}
rc.SetLabel("foo", "example.tld")
rc.SetTarget("1.2.3.4")
return &rc
}
func TestPreprocess_BoolValidation(t *testing.T) {
cf := &CloudflareApi{}
domain := newDomainConfig()
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "on"}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "fUll"}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "Off"}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "off"}})
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "fUll"}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "Off"}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "off"}))
err := cf.preprocessConfig(domain)
if err != nil {
t.Fatal(err)
@ -51,9 +62,9 @@ func TestPreprocess_DefaultProxy(t *testing.T) {
cf := &CloudflareApi{}
domain := newDomainConfig()
domain.Metadata[metaProxyDefault] = "full"
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "on"}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "off"}})
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{}})
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "off"}))
domain.Records = append(domain.Records, makeRCmeta(map[string]string{}))
err := cf.preprocessConfig(domain)
if err != nil {
t.Fatal(err)
@ -97,7 +108,8 @@ func TestIpRewriting(t *testing.T) {
NewBases: []net.IP{net.ParseIP("255.255.255.0")},
NewIPs: nil}}
for _, tst := range tests {
rec := &models.RecordConfig{Type: "A", Target: tst.Given, Metadata: map[string]string{metaProxy: tst.Proxy}}
rec := &models.RecordConfig{Type: "A", Metadata: map[string]string{metaProxy: tst.Proxy}}
rec.SetTarget(tst.Given)
domain.Records = append(domain.Records, rec)
}
err := cf.preprocessConfig(domain)
@ -106,8 +118,8 @@ func TestIpRewriting(t *testing.T) {
}
for i, tst := range tests {
rec := domain.Records[i]
if rec.Target != tst.Expected {
t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.Target)
if rec.GetTargetField() != tst.Expected {
t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.GetTargetField())
}
if tst.Proxy == "full" && tst.Given != tst.Expected && rec.Metadata[metaOriginalIP] != tst.Given {
t.Fatalf("At index %d, expected original_ip to be set", i)

View file

@ -77,7 +77,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
if d.matchIgnored(e.GetLabel()) {
log.Printf("Ignoring record %s %s due to IGNORE", e.GetLabel(), e.Type)
} else {
k := key{e.NameFQDN, e.Type}
k := key{e.GetLabelFQDN(), e.Type}
existingByNameAndType[k] = append(existingByNameAndType[k], e)
}
}
@ -85,7 +85,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
if d.matchIgnored(dr.GetLabel()) {
panic(fmt.Sprintf("Trying to update/add IGNOREd record: %s %s", dr.GetLabel(), dr.Type))
} else {
k := key{dr.NameFQDN, dr.Type}
k := key{dr.GetLabelFQDN(), dr.Type}
desiredByNameAndType[k] = append(desiredByNameAndType[k], dr)
}
}
@ -106,7 +106,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
for i := len(existingRecords) - 1; i >= 0; i-- {
ex := existingRecords[i]
for j, de := range desiredRecords {
if de.Target == ex.Target {
if de.GetTargetField() == ex.GetTargetField() {
// they're either identical or should be a modification of each other (ttl or metadata changes)
if d.content(de) == d.content(ex) {
unchanged = append(unchanged, Correlation{d, ex, de})
@ -197,12 +197,12 @@ func (d *differ) ChangedGroups(existing []*models.RecordConfig) map[models.Recor
func (c Correlation) String() string {
if c.Existing == nil {
return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.NameFQDN, c.d.content(c.Desired))
return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.GetLabelFQDN(), c.d.content(c.Desired))
}
if c.Desired == nil {
return fmt.Sprintf("DELETE %s %s %s", c.Existing.Type, c.Existing.NameFQDN, c.d.content(c.Existing))
return fmt.Sprintf("DELETE %s %s %s", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing))
}
return fmt.Sprintf("MODIFY %s %s: (%s) -> (%s)", c.Existing.Type, c.Existing.NameFQDN, c.d.content(c.Existing), c.d.content(c.Desired))
return fmt.Sprintf("MODIFY %s %s: (%s) -> (%s)", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing), c.d.content(c.Desired))
}
func sortedKeys(m map[string]*models.RecordConfig) []string {

View file

@ -7,20 +7,19 @@ import (
"testing"
"github.com/StackExchange/dnscontrol/models"
"github.com/miekg/dns/dnsutil"
)
func myRecord(s string) *models.RecordConfig {
parts := strings.Split(s, " ")
ttl, _ := strconv.ParseUint(parts[2], 10, 32)
return &models.RecordConfig{
Name: parts[0],
NameFQDN: dnsutil.AddOrigin(parts[0], "example.com"),
r := &models.RecordConfig{
Type: parts[1],
TTL: uint32(ttl),
Target: parts[3],
Metadata: map[string]string{},
}
r.SetLabel(parts[0], "example.com")
r.SetTarget(parts[3])
return r
}
func TestAdditionsOnly(t *testing.T) {

View file

@ -203,7 +203,6 @@ func toRc(dc *models.DomainConfig, r *godo.DomainRecord) *models.RecordConfig {
t := &models.RecordConfig{
Type: r.Type,
Target: target,
TTL: uint32(r.TTL),
MxPreference: uint16(r.Priority),
SrvPriority: uint16(r.Priority),
@ -212,6 +211,7 @@ func toRc(dc *models.DomainConfig, r *godo.DomainRecord) *models.RecordConfig {
Original: r,
}
t.SetLabelFromFQDN(name, dc.Name)
t.SetTarget(target)
switch rtype := r.Type; rtype {
case "TXT":
t.SetTargetTXTString(target)

View file

@ -10,7 +10,6 @@ import (
"github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers"
"github.com/StackExchange/dnscontrol/providers/diff"
"github.com/miekg/dns/dnsutil"
"github.com/pkg/errors"
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
@ -281,7 +280,7 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
return err
}
record := dnsimpleapi.ZoneRecord{
Name: dnsutil.TrimDomainName(rc.NameFQDN, domainName),
Name: rc.GetLabel(),
Type: rc.Type,
Content: rc.GetTargetCombined(),
TTL: int(rc.TTL),
@ -327,7 +326,7 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R
}
record := dnsimpleapi.ZoneRecord{
Name: dnsutil.TrimDomainName(rc.NameFQDN, domainName),
Name: rc.GetLabel(),
Type: rc.Type,
Content: rc.GetTargetCombined(),
TTL: int(rc.TTL),
@ -374,7 +373,7 @@ func removeOtherNS(dc *models.DomainConfig) {
for _, rec := range dc.Records {
if rec.Type == "NS" {
// apex NS inside dnsimple are expected.
if rec.NameFQDN == dc.Name && strings.HasSuffix(rec.GetTargetField(), ".dnsimple.com.") {
if rec.GetLabelFQDN() == dc.Name && strings.HasSuffix(rec.GetTargetField(), ".dnsimple.com.") {
continue
}
fmt.Printf("Warning: dnsimple.com does not allow NS records to be modified. %s will not be added.\n", rec.GetTargetField())

View file

@ -99,11 +99,11 @@ func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr
return nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
}
if rec.Type == "TXT" {
rec.Target = "\"" + rec.Target + "\"" // FIXME(tlim): Should do proper quoting.
rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting.
}
if rec.Type == "NS" && rec.GetLabel() == "@" {
if !strings.HasSuffix(rec.Target, ".gandi.net.") {
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.Target)
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.GetTargetField())
}
continue
}

View file

@ -223,31 +223,31 @@ func (c *liveClient) recordsToInfo(records models.Records) (models.Records, []*g
for _, rec := range records {
if rec.TTL < 300 {
log.Printf("WARNING: Gandi does not support ttls < 300. %s will not be set to %d.", rec.NameFQDN, rec.TTL)
log.Printf("WARNING: Gandi does not support ttls < 300. %s will not be set to %d.", rec.GetLabelFQDN(), rec.TTL)
rec.TTL = 300
}
if rec.TTL > 2592000 {
return nil, nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
}
if rec.Type == "NS" && rec.Name == "@" {
if !strings.HasSuffix(rec.Target, ".gandi.net.") {
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.Target)
if rec.Type == "NS" && rec.GetLabel() == "@" {
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.GetTargetField())
}
continue
}
r, ok := recordSets[rec.Name][rec.Type]
r, ok := recordSets[rec.GetLabel()][rec.Type]
if !ok {
_, ok := recordSets[rec.Name]
_, ok := recordSets[rec.GetLabel()]
if !ok {
recordSets[rec.Name] = map[string]*gandiliverecord.Info{}
recordSets[rec.GetLabel()] = map[string]*gandiliverecord.Info{}
}
r = &gandiliverecord.Info{
Type: rec.Type,
Name: rec.Name,
Name: rec.GetLabel(),
TTL: int64(rec.TTL),
}
recordInfos = append(recordInfos, r)
recordSets[rec.Name][rec.Type] = r
recordSets[rec.GetLabel()][rec.Type] = r
} else {
if r.TTL != int64(rec.TTL) {
log.Printf(

View file

@ -8,6 +8,11 @@ import (
"github.com/stretchr/testify/assert"
)
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
rc.SetLabel(label, domain)
rc.SetTarget(target)
return &rc
}
func TestRecordConfigFromInfo(t *testing.T) {
for _, data := range []struct {
@ -22,20 +27,14 @@ func TestRecordConfigFromInfo(t *testing.T) {
Values: []string{"127.0.0.1", "127.1.0.1"},
},
[]*models.RecordConfig{
{
NameFQDN: "www.example.com",
Name: "www",
Type: "A",
Target: "127.0.0.1",
TTL: 500,
},
{
NameFQDN: "www.example.com",
Name: "www",
Type: "A",
Target: "127.1.0.1",
TTL: 500,
},
makeRC("www", "example.com", "127.0.0.1", models.RecordConfig{
Type: "A",
TTL: 500,
}),
makeRC("www", "example.com", "127.1.0.1", models.RecordConfig{
Type: "A",
TTL: 500,
}),
},
},
{
@ -46,14 +45,11 @@ func TestRecordConfigFromInfo(t *testing.T) {
Values: []string{"\"test 2\"", "\"test message test message test message\""},
},
[]*models.RecordConfig{
{
NameFQDN: "www.example.com",
Name: "www",
makeRC("www", "example.com", "test 2", models.RecordConfig{
Type: "TXT",
Target: "test 2",
TxtStrings: []string{"test 2", "test message test message test message"},
TTL: 500,
},
}),
},
},
{
@ -65,24 +61,18 @@ func TestRecordConfigFromInfo(t *testing.T) {
Values: []string{"0 issue \"www.certinomis.com\"", "0 issuewild \"buypass.com\""},
},
[]*models.RecordConfig{
{
NameFQDN: "www.example.com",
Name: "www",
Type: "CAA",
Target: "www.certinomis.com",
CaaFlag: 0,
CaaTag: "issue",
TTL: 500,
},
{
NameFQDN: "www.example.com",
Name: "www",
Type: "CAA",
Target: "buypass.com",
CaaFlag: 0,
CaaTag: "issuewild",
TTL: 500,
},
makeRC("www", "example.com", "www.certinomis.com", models.RecordConfig{
Type: "CAA",
CaaFlag: 0,
CaaTag: "issue",
TTL: 500,
}),
makeRC("www", "example.com", "buypass.com", models.RecordConfig{
Type: "CAA",
CaaFlag: 0,
CaaTag: "issuewild",
TTL: 500,
}),
},
},
{
@ -93,16 +83,13 @@ func TestRecordConfigFromInfo(t *testing.T) {
Values: []string{"20 0 5060 backupbox.example.com."},
},
[]*models.RecordConfig{
{
NameFQDN: "test.example.com",
Name: "test",
makeRC("test", "example.com", "backupbox.example.com.", models.RecordConfig{
Type: "SRV",
Target: "backupbox.example.com.",
SrvPriority: 20,
SrvWeight: 0,
SrvPort: 5060,
TTL: 500,
},
}),
},
},
{
@ -113,22 +100,16 @@ func TestRecordConfigFromInfo(t *testing.T) {
Values: []string{"50 fb.mail.gandi.net.", "10 spool.mail.gandi.net."},
},
[]*models.RecordConfig{
{
NameFQDN: "mail.example.com",
Name: "mail",
makeRC("mail", "example.com", "fb.mail.gandi.net.", models.RecordConfig{
Type: "MX",
MxPreference: 50,
Target: "fb.mail.gandi.net.",
TTL: 500,
},
{
NameFQDN: "mail.example.com",
Name: "mail",
}),
makeRC("mail", "example.com", "spool.mail.gandi.net.", models.RecordConfig{
Type: "MX",
MxPreference: 10,
Target: "spool.mail.gandi.net.",
TTL: 500,
},
}),
},
},
} {

View file

@ -104,7 +104,7 @@ func keyFor(r *gdns.ResourceRecordSet) key {
return key{Type: r.Type, Name: r.Name}
}
func keyForRec(r *models.RecordConfig) key {
return key{Type: r.Type, Name: r.NameFQDN + "."}
return key{Type: r.Type, Name: r.GetLabelFQDN() + "."}
}
func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {

View file

@ -136,10 +136,10 @@ func (api *LinodeApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C
// https://github.com/linode/manager/blob/edd99dc4e1be5ab8190f243c3dbf8b830716255e/src/constants.js#L184
for _, name := range defaultNameServerNames {
rc := &models.RecordConfig{
NameFQDN: dc.Name,
Type: "NS",
Original: &domainRecord{},
}
rc.SetLabelFromFQDN(dc.Name, dc.Name)
rc.SetTarget(name)
existingRecords = append(existingRecords, rc)
@ -249,7 +249,7 @@ func toRc(dc *models.DomainConfig, r *domainRecord) *models.RecordConfig {
func toReq(dc *models.DomainConfig, rc *models.RecordConfig) (*recordEditRequest, error) {
req := &recordEditRequest{
Type: rc.Type,
Name: dnsutil.TrimDomainName(rc.NameFQDN, dc.Name),
Name: rc.GetLabel(),
Target: rc.GetTargetField(),
TTL: int(rc.TTL),
Priority: 0,

View file

@ -14,7 +14,6 @@ import (
"github.com/StackExchange/dnscontrol/providers"
"github.com/StackExchange/dnscontrol/providers/diff"
nc "github.com/billputer/go-namecheap"
"github.com/miekg/dns/dnsutil"
"github.com/pkg/errors"
)
@ -125,9 +124,9 @@ func (n *Namecheap) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Cor
// namecheap does not allow setting @ NS with basic DNS
dc.Filter(func(r *models.RecordConfig) bool {
if r.Type == "NS" && r.Name == "@" {
if !strings.HasSuffix(r.Target, "registrar-servers.com.") {
fmt.Println("\n", r.Target, "Namecheap does not support changing apex NS records. Skipping.")
if r.Type == "NS" && r.GetLabel() == "@" {
if !strings.HasSuffix(r.GetTargetField(), "registrar-servers.com.") {
fmt.Println("\n", r.GetTargetField(), "Namecheap does not support changing apex NS records. Skipping.")
}
return false
}
@ -150,13 +149,13 @@ func (n *Namecheap) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Cor
continue
}
rec := &models.RecordConfig{
NameFQDN: dnsutil.AddOrigin(r.Name, dc.Name),
Type: r.Type,
Target: r.Address,
TTL: uint32(r.TTL),
MxPreference: uint16(r.MXPref),
Original: r,
}
rec.SetLabel(r.Name, dc.Name)
rec.SetTarget(r.Address)
actual = append(actual, rec)
}
@ -204,12 +203,11 @@ func (n *Namecheap) generateRecords(dc *models.DomainConfig) error {
id := 1
for _, r := range dc.Records {
name := dnsutil.TrimDomainName(r.NameFQDN, dc.Name)
rec := nc.DomainDNSHost{
ID: id,
Name: name,
Name: r.GetLabel(),
Type: r.Type,
Address: r.Target,
Address: r.GetTargetField(),
MXPref: int(r.MxPreference),
TTL: int(r.TTL),
}

View file

@ -8,8 +8,6 @@ import (
"github.com/namedotcom/go/namecom"
"github.com/pkg/errors"
"github.com/miekg/dns/dnsutil"
"github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers/diff"
)
@ -76,7 +74,7 @@ func (n *NameCom) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corre
func checkNSModifications(dc *models.DomainConfig) {
newList := make([]*models.RecordConfig, 0, len(dc.Records))
for _, rec := range dc.Records {
if rec.Type == "NS" && rec.NameFQDN == dc.Name {
if rec.Type == "NS" && rec.GetLabel() == "@" {
continue // Apex NS records are automatically created for the domain's nameservers and cannot be managed otherwise via the name.com API.
}
newList = append(newList, rec)
@ -147,9 +145,9 @@ func (n *NameCom) getRecords(domain string) ([]*namecom.Record, error) {
func (n *NameCom) createRecord(rc *models.RecordConfig, domain string) error {
record := &namecom.Record{
DomainName: domain,
Host: dnsutil.TrimDomainName(rc.NameFQDN, domain),
Host: rc.GetLabel(),
Type: rc.Type,
Answer: rc.Target,
Answer: rc.GetTargetField(),
TTL: rc.TTL,
Priority: uint32(rc.MxPreference),
}
@ -159,7 +157,7 @@ func (n *NameCom) createRecord(rc *models.RecordConfig, domain string) error {
case "TXT":
record.Answer = encodeTxt(rc.TxtStrings)
case "SRV":
record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, rc.Target)
record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, rc.GetTargetField())
record.Priority = uint32(rc.SrvPriority)
default:
panic(fmt.Sprintf("createRecord rtype %v unimplemented", rc.Type))

View file

@ -178,7 +178,7 @@ func parseLeaf(results models.Records, k string, v interface{}, origin string) (
case "port": // SRV
newRc.SrvPort = uint16(v4.(int))
case "value": // MX
newRc.Target = v4.(string)
newRc.SetTarget(v4.(string))
}
}
//fmt.Printf("parseLeaf: append %v\n", newRc)

View file

@ -56,7 +56,9 @@ func TestYamlWrite(t *testing.T) {
m.AddFunc("json", minjson.Minify)
t.Run(f.Name(), func(t *testing.T) {
content, err := ioutil.ReadFile(filepath.Join(testDir, f.Name()))
fname := filepath.Join(testDir, f.Name())
fmt.Printf("Filename: %v\n", fname)
content, err := ioutil.ReadFile(fname)
if err != nil {
t.Fatal(err)
}

View file

@ -48,14 +48,14 @@ func (z *genYamlData) Less(i, j int) bool {
case "NS", "TXT", "TLSA":
// pass through.
case "A":
ta2, tb2 := net.ParseIP(a.Target), net.ParseIP(b.Target)
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.Target), net.ParseIP(b.Target)
ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField())
ipa, ipb := ta2.To16(), tb2.To16()
return bytes.Compare(ipa, ipb) == -1
case "MX":
@ -75,7 +75,7 @@ func (z *genYamlData) Less(i, j int) bool {
return pa < pb
}
case "PTR":
pa, pb := a.Target, b.Target
pa, pb := a.GetTargetField(), b.GetTargetField()
if pa != pb {
return pa < pb
}

View file

@ -28,8 +28,9 @@ func WriteYaml(w io.Writer, records models.Records, origin string) error {
recsCopy = append(recsCopy, r)
}
for _, r := range recsCopy {
if r.Name == "@" {
r.Name = ""
if r.GetLabel() == "@" {
//r.Name = ""
r.UnsafeSetLabelNull()
}
}
@ -156,7 +157,7 @@ func sameType(records models.Records) bool {
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].Name,
Key: records[0].GetLabel(),
}
// Special case labels with a single record:
if len(records) == 1 {

View file

@ -112,7 +112,7 @@ func (c *ovhProvider) deleteRecordFunc(id int64, fqdn string) func() error {
func (c *ovhProvider) createRecordFunc(rc *models.RecordConfig, fqdn string) func() error {
return func() error {
record := Record{
SubDomain: dnsutil.TrimDomainName(rc.NameFQDN, fqdn),
SubDomain: dnsutil.TrimDomainName(rc.GetLabelFQDN(), fqdn),
FieldType: rc.Type,
Target: rc.GetTargetCombined(),
TTL: rc.TTL,
@ -130,7 +130,7 @@ func (c *ovhProvider) createRecordFunc(rc *models.RecordConfig, fqdn string) fun
func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqdn string) func() error {
return func() error {
record := Record{
SubDomain: dnsutil.TrimDomainName(rc.NameFQDN, fqdn),
SubDomain: rc.GetLabel(),
FieldType: rc.Type,
Target: rc.GetTargetCombined(),
TTL: rc.TTL,

View file

@ -9,7 +9,6 @@ import (
"github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers"
"github.com/StackExchange/dnscontrol/providers/diff"
"github.com/miekg/dns/dnsutil"
"github.com/pkg/errors"
"github.com/softlayer/softlayer-go/datatypes"
@ -129,10 +128,10 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
recConfig := &models.RecordConfig{
Type: recType,
Target: *record.Data,
TTL: uint32(*record.Ttl),
Original: record,
}
recConfig.SetTarget(*record.Data)
switch recType {
case "SRV":
@ -153,21 +152,16 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
if record.Service != nil {
service = *record.Service
}
recConfig.Name = fmt.Sprintf("%s.%s", service, strings.ToLower(protocol))
recConfig.SetLabel(fmt.Sprintf("%s.%s", service, strings.ToLower(protocol)), *domain.Name)
case "MX":
if record.MxPriority != nil {
recConfig.MxPreference = uint16(*record.MxPriority)
}
fallthrough
default:
recConfig.Name = *record.Host
recConfig.SetLabel(*record.Host, *domain.Name)
}
recConfig.NameFQDN = dnsutil.AddOrigin(recConfig.Name, *domain.Name)
actual = append(actual, recConfig)
}
@ -180,7 +174,7 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
func (s *SoftLayer) createRecordFunc(desired *models.RecordConfig, domain *datatypes.Dns_Domain) func() error {
var ttl, preference, domainID int = int(desired.TTL), int(desired.MxPreference), *domain.Id
var weight, priority, port int = int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort)
var host, data, newType string = desired.Name, desired.Target, desired.Type
var host, data, newType string = desired.GetLabel(), desired.GetTargetField(), desired.Type
var err error
srvRegexp := regexp.MustCompile(`^_(?P<Service>\w+)\.\_(?P<Protocol>\w+)$`)
@ -260,13 +254,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
service := services.GetDnsDomainResourceRecordMxTypeService(s.Session)
updated := datatypes.Dns_Domain_ResourceRecord_MxType{}
if desired.Name != *existing.Host {
updated.Host = &desired.Name
label := desired.GetLabel()
if label != *existing.Host {
updated.Host = &label
changes = true
}
if desired.Target != *existing.Data {
updated.Data = &desired.Target
target := desired.GetTargetField()
if target != *existing.Data {
updated.Data = &target
changes = true
}
@ -290,13 +286,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
service := services.GetDnsDomainResourceRecordSrvTypeService(s.Session)
updated := datatypes.Dns_Domain_ResourceRecord_SrvType{}
if desired.Name != *existing.Host {
updated.Host = &desired.Name
label := desired.GetLabel()
if label != *existing.Host {
updated.Host = &label
changes = true
}
if desired.Target != *existing.Data {
updated.Data = &desired.Target
target := desired.GetTargetField()
if target != *existing.Data {
updated.Data = &target
changes = true
}
@ -333,13 +331,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
service := services.GetDnsDomainResourceRecordService(s.Session)
updated := datatypes.Dns_Domain_ResourceRecord{}
if desired.Name != *existing.Host {
updated.Host = &desired.Name
label := desired.GetLabel()
if label != *existing.Host {
updated.Host = &label
changes = true
}
if desired.Target != *existing.Data {
updated.Data = &desired.Target
target := desired.GetTargetField()
if target != *existing.Data {
updated.Data = &target
changes = true
}

View file

@ -234,7 +234,7 @@ func toRecordConfig(dc *models.DomainConfig, r *vultr.DNSRecord) (*models.Record
// toVultrRecord converts a RecordConfig converted by toRecordConfig back to a Vultr DNSRecord #rtype_variations
func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig) *vultr.DNSRecord {
name := dnsutil.TrimDomainName(rc.NameFQDN, dc.Name)
name := rc.GetLabel()
// Vultr uses a blank string to represent the apex domain
if name == "@" {
name = ""
@ -267,17 +267,16 @@ func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig) *vultr.DNSR
TTL: int(rc.TTL),
Priority: priority,
}
if rc.Type == "SRV" {
target := rc.Target
switch rtype := rc.Type; rtype { // #rtype_variations
case "SRV":
target := rc.GetTargetField()
if strings.HasSuffix(target, ".") {
target = target[:len(target)-1]
}
r.Data = fmt.Sprintf("%v %v %s", rc.SrvWeight, rc.SrvPort, target)
}
if rc.Type == "CAA" {
case "CAA":
r.Data = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
default:
}
return r