dnscontrol/providers/octodns/octoyaml/sort.go
Patrick Gaskin 2f83aa9302 Internals: Switch to v2 go.mod, drop GOPATH, and fix Azure Pipelines (#595)
* Switched to v2 go.mod

Also set GO111MODULE=on in build stuff to always use Go modules
even when in GOPATH.

* Ensure go.mod, go.sum, and vendor are up to date

* Attempt to fix Azure pipelines

* Add set -e to properly fail on exit (it didn't seem to be
  propagating properly before).
* Set workingDirectory for GoFmt and GoGen (this might be why it
  fails unlike compile and unitests).

* Another attempt to fix Azure Pipelines

* Use the Go env template for all go-related jobs.

* Completely fixed Azure Pipelines

* Added a display name to GoFmt for consistency.
* Fixed diffs for GoFmt and GoGen.
* Show git status for checks.

* Drop GOPATH for tests

TODO: Do the same for integration tests.

* Drop GOPATH for integration tests

* Show more diffs

* Regenerate provider support matrix

This wasn't done in #590...
2020-01-28 10:42:31 -05:00

136 lines
3.2 KiB
Go

package octoyaml
import (
"bytes"
"fmt"
"log"
"net"
"sort"
"github.com/StackExchange/dnscontrol/v2/models"
"github.com/StackExchange/dnscontrol/v2/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
}