github.com/teknogeek/dnscontrol@v0.2.8/providers/octodns/octoyaml/sort.go (about)

     1  package octoyaml
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"net"
     8  	"sort"
     9  
    10  	"github.com/StackExchange/dnscontrol/models"
    11  	"github.com/StackExchange/dnscontrol/pkg/natsort"
    12  	"github.com/miekg/dns/dnsutil"
    13  )
    14  
    15  type genYamlData struct {
    16  	Origin     string
    17  	DefaultTTL uint32
    18  	Records    models.Records
    19  }
    20  
    21  func sortRecs(recs models.Records, origin string) {
    22  	z := &genYamlData{
    23  		Origin:  dnsutil.AddOrigin(origin, "."),
    24  		Records: recs,
    25  	}
    26  	sort.Sort(z)
    27  }
    28  
    29  func (z *genYamlData) Len() int      { return len(z.Records) }
    30  func (z *genYamlData) Swap(i, j int) { z.Records[i], z.Records[j] = z.Records[j], z.Records[i] }
    31  func (z *genYamlData) Less(i, j int) bool {
    32  	a, b := z.Records[i], z.Records[j]
    33  	compA, compB := a.GetLabel(), b.GetLabel()
    34  	if compA != compB {
    35  		if compA == z.Origin+"." {
    36  			compA = "@"
    37  		}
    38  		if compB == z.Origin+"." {
    39  			compB = "@"
    40  		}
    41  		return zoneLabelLess(compA, compB)
    42  	}
    43  	rrtypeA, rrtypeB := a.Type, b.Type
    44  	if rrtypeA != rrtypeB {
    45  		return zoneRrtypeLess(rrtypeA, rrtypeB)
    46  	}
    47  	switch rrtypeA { // #rtype_variations
    48  	case "NS", "TXT", "TLSA":
    49  		// pass through.
    50  	case "A":
    51  		ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField())
    52  		ipa, ipb := ta2.To4(), tb2.To4()
    53  		if ipa == nil || ipb == nil {
    54  			log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2)
    55  		}
    56  		return bytes.Compare(ipa, ipb) == -1
    57  	case "AAAA":
    58  		ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField())
    59  		ipa, ipb := ta2.To16(), tb2.To16()
    60  		return bytes.Compare(ipa, ipb) == -1
    61  	case "MX":
    62  		pa, pb := a.MxPreference, b.MxPreference
    63  		return pa < pb
    64  	case "SRV":
    65  		pa, pb := a.SrvPort, b.SrvPort
    66  		if pa != pb {
    67  			return pa < pb
    68  		}
    69  		pa, pb = a.SrvPriority, b.SrvPriority
    70  		if pa != pb {
    71  			return pa < pb
    72  		}
    73  		pa, pb = a.SrvWeight, a.SrvWeight
    74  		if pa != pb {
    75  			return pa < pb
    76  		}
    77  	case "PTR":
    78  		pa, pb := a.GetTargetField(), b.GetTargetField()
    79  		if pa != pb {
    80  			return pa < pb
    81  		}
    82  	case "CAA":
    83  		// sort by tag
    84  		pa, pb := a.CaaTag, b.CaaTag
    85  		if pa != pb {
    86  			return pa < pb
    87  		}
    88  		// then flag
    89  		fa, fb := a.CaaFlag, b.CaaFlag
    90  		if fa != fb {
    91  			// flag set goes before ones without flag set
    92  			return fa > fb
    93  		}
    94  	default:
    95  		panic(fmt.Sprintf("genYamlData Less: unimplemented rtype %v", a.Type))
    96  		// We panic so that we quickly find any switch statements
    97  		// that have not been updated for a new RR type.
    98  	}
    99  	return a.GetTargetSortable() < b.GetTargetSortable()
   100  }
   101  
   102  func zoneLabelLess(a, b string) bool {
   103  	return natsort.Less(a, b)
   104  	// octodns-validate wants a "natural sort" (i.e. foo10 comes after foo3).
   105  	// We emulate this with the natsort package.
   106  	// If you need to disable that validatation:
   107  	//    Edit env/lib/python2.7/site-packages/octodns/yaml.py
   108  	//    Change line 27: OLD: if key != expected
   109  	//                    NEW: if False and key != expected
   110  }
   111  
   112  func zoneRrtypeLess(a, b string) bool {
   113  	// Compare two RR types for the purpose of sorting the RRs in a Zone.
   114  
   115  	// If they are equal, we are done. All other code is simplified
   116  	// because we can assume a!=b.
   117  	if a == b {
   118  		return false
   119  	}
   120  
   121  	// List SOAs, then NSs, then all others.
   122  	// i.e. SOA is always less. NS is less than everything but SOA.
   123  	if a == "SOA" {
   124  		return true
   125  	}
   126  	if b == "SOA" {
   127  		return false
   128  	}
   129  	if a == "NS" {
   130  		return true
   131  	}
   132  	if b == "NS" {
   133  		return false
   134  	}
   135  	return a < b
   136  }