1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

HEDNS: Add full Diff2 support (#1915)

Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
Robert Blenkinsopp
2023-01-09 21:20:03 +00:00
committed by GitHub
parent 80fcc5232e
commit 99a0eb84f6

View File

@@ -51,6 +51,7 @@ var features = providers.DocumentationNotes{
providers.CanUseDSForChildren: providers.Cannot(), providers.CanUseDSForChildren: providers.Cannot(),
providers.CanUseNAPTR: providers.Can(), providers.CanUseNAPTR: providers.Can(),
providers.CanUsePTR: providers.Can(), providers.CanUsePTR: providers.Can(),
providers.CanUseSOA: providers.Cannot(),
providers.CanUseSRV: providers.Can(), providers.CanUseSRV: providers.Can(),
providers.CanUseSSHFP: providers.Can(), providers.CanUseSSHFP: providers.Can(),
providers.CanUseTLSA: providers.Cannot(), providers.CanUseTLSA: providers.Cannot(),
@@ -204,57 +205,92 @@ func (c *hednsProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models
models.PostProcessRecords(prunedRecords) models.PostProcessRecords(prunedRecords)
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
// Fallback to legacy mode if diff2 is not enabled, remove when diff1 is deprecated.
if !diff2.EnableDiff2 {
return c.getDiff1DomainCorrections(dc, zoneID, prunedRecords)
} else {
return c.getDiff2DomainCorrections(dc, zoneID, prunedRecords)
}
}
func (c *hednsProvider) getDiff1DomainCorrections(dc *models.DomainConfig, zoneID uint64, records models.Records) ([]*models.Correction, error) {
var corrections []*models.Correction var corrections []*models.Correction
var toCreate, toDelete, toModify diff.Changeset var toCreate, toDelete, toModify diff.Changeset
if !diff2.EnableDiff2 {
differ := diff.New(dc) differ := diff.New(dc)
_, toCreate, toDelete, toModify, err = differ.IncrementalDiff(prunedRecords) _, toCreate, toDelete, toModify, err := differ.IncrementalDiff(records)
} else {
differ := diff.NewCompat(dc)
_, toCreate, toDelete, toModify, err = differ.IncrementalDiff(prunedRecords)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, del := range toDelete { for _, del := range toDelete {
record := del.Existing recordID := del.Existing.Original.(Record).RecordID
corrections = append(corrections, &models.Correction{ corrections = append(corrections, &models.Correction{
Msg: del.String(), Msg: del.String(),
F: func() error { return c.deleteZoneRecord(record) }, F: func() error { return c.deleteZoneRecord(zoneID, recordID) },
}) })
} }
for _, cre := range toCreate { for _, cre := range toCreate {
record := cre.Desired record := cre.Desired
record.Original = Record{
ZoneName: dc.Name,
ZoneID: zoneID,
RecordName: cre.Desired.Name,
}
corrections = append(corrections, &models.Correction{ corrections = append(corrections, &models.Correction{
Msg: cre.String(), Msg: cre.String(),
F: func() error { return c.editZoneRecord(record, true) }, F: func() error { return c.createZoneRecord(zoneID, record) },
}) })
} }
for _, mod := range toModify { for _, mod := range toModify {
record := mod.Desired record := mod.Desired
record.Original = Record{ recordID := mod.Existing.Original.(Record).RecordID
ZoneName: dc.Name,
ZoneID: zoneID,
RecordID: mod.Existing.Original.(Record).RecordID,
RecordName: mod.Desired.Name,
}
corrections = append(corrections, &models.Correction{ corrections = append(corrections, &models.Correction{
Msg: mod.String(), Msg: mod.String(),
F: func() error { return c.editZoneRecord(record, false) }, F: func() error { return c.changeZoneRecord(zoneID, recordID, record) },
}) })
} }
return corrections, nil return corrections, nil
} }
func (c *hednsProvider) getDiff2DomainCorrections(dc *models.DomainConfig, zoneID uint64, records models.Records) ([]*models.Correction, error) {
changes, err := diff2.ByRecord(records, dc, nil)
if err != nil {
return nil, err
}
var corrections []*models.Correction
for _, change := range changes {
switch change.Type {
case diff2.CREATE:
record := change.New[0]
corrections = append(corrections, &models.Correction{
Msg: change.MsgsJoined,
F: func() error {
return c.createZoneRecord(zoneID, record)
},
})
case diff2.CHANGE:
record := change.New[0]
recordID := change.Old[0].Original.(Record).RecordID
corrections = append(corrections, &models.Correction{
Msg: change.MsgsJoined,
F: func() error {
return c.changeZoneRecord(zoneID, recordID, record)
},
})
case diff2.DELETE:
recordID := change.Old[0].Original.(Record).RecordID
corrections = append(corrections, &models.Correction{
Msg: change.MsgsJoined,
F: func() error {
return c.deleteZoneRecord(zoneID, recordID)
},
})
}
}
return corrections, nil
}
// GetZoneRecords returns all the records for the given domain // GetZoneRecords returns all the records for the given domain
func (c *hednsProvider) GetZoneRecords(domain string) (models.Records, error) { func (c *hednsProvider) GetZoneRecords(domain string) (models.Records, error) {
var zoneRecords []*models.RecordConfig var zoneRecords []*models.RecordConfig
@@ -332,9 +368,9 @@ func (c *hednsProvider) GetZoneRecords(domain string) (models.Records, error) {
err = rc.SetTarget(data) err = rc.SetTarget(data)
case "MX": case "MX":
// dns.he.net omits the trailing "." on the hostnames for MX records // dns.he.net omits the trailing "." on the hostnames for MX records
err = rc.SetTargetMX(uint16(priority), data+".") err = rc.SetTargetMX(priority, data+".")
case "SRV": case "SRV":
err = rc.SetTargetSRVPriorityString(uint16(priority), data) err = rc.SetTargetSRVPriorityString(priority, data)
case "SPF": case "SPF":
// Convert to TXT record as SPF is deprecated // Convert to TXT record as SPF is deprecated
rc.Type = "TXT" rc.Type = "TXT"
@@ -540,11 +576,11 @@ func (c *hednsProvider) createDomain(domain string) error {
return err return err
} }
func (c *hednsProvider) editZoneRecord(rc *models.RecordConfig, create bool) error { func (c *hednsProvider) editZoneRecord(zoneID uint64, recordID uint64, rc *models.RecordConfig, create bool) error {
values := url.Values{ values := url.Values{
"account": {}, "account": {},
"menu": {"edit_zone"}, "menu": {"edit_zone"},
"hosted_dns_zoneid": {strconv.FormatUint(rc.Original.(Record).ZoneID, 10)}, "hosted_dns_zoneid": {strconv.FormatUint(zoneID, 10)},
"hosted_dns_editzone": {"1"}, "hosted_dns_editzone": {"1"},
"TTL": {strconv.FormatUint(uint64(rc.TTL), 10)}, "TTL": {strconv.FormatUint(uint64(rc.TTL), 10)},
"Name": {rc.Name}, "Name": {rc.Name},
@@ -555,16 +591,11 @@ func (c *hednsProvider) editZoneRecord(rc *models.RecordConfig, create bool) err
values.Set("Type", rc.Type) values.Set("Type", rc.Type)
values.Set("hosted_dns_editrecord", "Submit") values.Set("hosted_dns_editrecord", "Submit")
values.Set("hosted_dns_recordid", "") values.Set("hosted_dns_recordid", "")
values.Set("Priority", "")
} else { } else {
values.Set("Type", strings.ToLower(rc.Type)) // Lowercase on update values.Set("Type", strings.ToLower(rc.Type)) // Lowercase on update
values.Set("hosted_dns_editrecord", "Update") values.Set("hosted_dns_editrecord", "Update")
values.Set("hosted_dns_recordid", strconv.FormatUint(rc.Original.(Record).RecordID, 10)) values.Set("hosted_dns_recordid", strconv.FormatUint(recordID, 10))
}
// Handle priorities
if create {
values.Set("Priority", "")
} else {
values.Set("Priority", "-") values.Set("Priority", "-")
} }
@@ -593,11 +624,19 @@ func (c *hednsProvider) editZoneRecord(rc *models.RecordConfig, create bool) err
return err return err
} }
func (c *hednsProvider) deleteZoneRecord(rc *models.RecordConfig) error { func (c *hednsProvider) createZoneRecord(zoneID uint64, rc *models.RecordConfig) error {
return c.editZoneRecord(zoneID, 0, rc, true)
}
func (c *hednsProvider) changeZoneRecord(zoneID uint64, recordID uint64, rc *models.RecordConfig) error {
return c.editZoneRecord(zoneID, recordID, rc, false)
}
func (c *hednsProvider) deleteZoneRecord(zoneID uint64, recordID uint64) error {
values := url.Values{ values := url.Values{
"menu": {"edit_zone"}, "menu": {"edit_zone"},
"hosted_dns_zoneid": {strconv.FormatUint(rc.Original.(Record).ZoneID, 10)}, "hosted_dns_zoneid": {strconv.FormatUint(zoneID, 10)},
"hosted_dns_recordid": {strconv.FormatUint(rc.Original.(Record).RecordID, 10)}, "hosted_dns_recordid": {strconv.FormatUint(recordID, 10)},
"hosted_dns_editzone": {"1"}, "hosted_dns_editzone": {"1"},
"hosted_dns_delrecord": {"1"}, "hosted_dns_delrecord": {"1"},
"hosted_dns_delconfirm": {"delete"}, "hosted_dns_delconfirm": {"delete"},