github.com/StackExchange/DNSControl@v0.2.8/providers/bind/serial.go (about)

     1  package bind
     2  
     3  import (
     4  	"log"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  )
     9  
    10  var nowFunc = time.Now
    11  
    12  // generateSerial takes an old SOA serial number and increments it.
    13  func generateSerial(oldSerial uint32) uint32 {
    14  	// Serial numbers are in the format yyyymmddvv
    15  	// where vv is a version count that starts at 01 each day.
    16  	// Multiple serial numbers generated on the same day increase vv.
    17  	// If the old serial number is not in this format, it gets replaced
    18  	// with the new format. However if that would mean a new serial number
    19  	// that is smaller than the old one, we punt and increment the old number.
    20  	// At no time will a serial number == 0 be returned.
    21  
    22  	original := oldSerial
    23  	oldSerialStr := strconv.FormatUint(uint64(oldSerial), 10)
    24  	var newSerial uint32
    25  
    26  	// Make draft new serial number:
    27  	today := nowFunc().UTC()
    28  	todayStr := today.Format("20060102")
    29  	version := uint32(1)
    30  	todayNum, err := strconv.ParseUint(todayStr, 10, 32)
    31  	if err != nil {
    32  		log.Fatalf("new serial won't fit in 32 bits: %v", err)
    33  	}
    34  	draft := uint32(todayNum)*100 + version
    35  
    36  	method := "none" // Used only in debugging.
    37  	if oldSerial > draft {
    38  		// If old_serial was really slow, upgrade to new yyyymmddvv standard:
    39  		method = "o>d"
    40  		newSerial = oldSerial + 1
    41  		newSerial = oldSerial + 1
    42  	} else if oldSerial == draft {
    43  		// Edge case: increment old serial:
    44  		method = "o=d"
    45  		newSerial = draft + 1
    46  	} else if len(oldSerialStr) != 10 {
    47  		// If old_serial is wrong number of digits, upgrade to yyyymmddvv standard:
    48  		method = "len!=10"
    49  		newSerial = draft
    50  	} else if strings.HasPrefix(oldSerialStr, todayStr) {
    51  		// If old_serial just needs to be incremented:
    52  		method = "prefix"
    53  		newSerial = oldSerial + 1
    54  	} else {
    55  		// First serial number to be requested today:
    56  		method = "default"
    57  		newSerial = draft
    58  	}
    59  
    60  	if newSerial == 0 {
    61  		// We never return 0 as the serial number.
    62  		newSerial = 1
    63  	}
    64  	if oldSerial == newSerial {
    65  		log.Fatalf("%v: old_serial == new_serial (%v == %v) draft=%v method=%v", original, oldSerial, newSerial, draft, method)
    66  	}
    67  	if oldSerial > newSerial {
    68  		log.Fatalf("%v: old_serial > new_serial (%v > %v) draft=%v method=%v", original, oldSerial, newSerial, draft, method)
    69  	}
    70  	return newSerial
    71  }