diff --git a/commands/previewPush.go b/commands/previewPush.go index f741ddbe5..e47fcada8 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -9,6 +9,7 @@ import ( "golang.org/x/net/idna" "github.com/StackExchange/dnscontrol/v3/models" + "github.com/StackExchange/dnscontrol/v3/pkg/bindserial" "github.com/StackExchange/dnscontrol/v3/pkg/credsfile" "github.com/StackExchange/dnscontrol/v3/pkg/diff2" "github.com/StackExchange/dnscontrol/v3/pkg/nameservers" @@ -68,6 +69,11 @@ func (args *PreviewArgs) flags() []cli.Flag { Destination: &args.Full, Usage: `Add headings, providers names, notifications of no changes, etc`, }) + flags = append(flags, &cli.Int64Flag{ + Name: "bindserial", + Destination: &bindserial.ForcedValue, + Usage: `Force BIND serial numbers to this value (for reproducibility)`, + }) return flags } diff --git a/pkg/bindserial/main.go b/pkg/bindserial/main.go new file mode 100644 index 000000000..e60fb5686 --- /dev/null +++ b/pkg/bindserial/main.go @@ -0,0 +1,11 @@ +package bindserial + +// NB(tlim): Yes, its gross to use a global variable for this. +// However there's no cleaner way to do it. Ideally we'd add a way to +// have per-provider flags or settings on the command line. At least +// by isolating it to this file we limit the blast radius of this bad +// decision. + +// ForceBindSerial if non-zero, BIND will generate SOA serial numbers +// using this value. +var ForcedValue int64 diff --git a/providers/bind/serial.go b/providers/bind/serial.go index 11f8549f7..b21093576 100644 --- a/providers/bind/serial.go +++ b/providers/bind/serial.go @@ -4,6 +4,8 @@ import ( "log" "strconv" "time" + + "github.com/StackExchange/dnscontrol/v3/pkg/bindserial" ) var nowFunc = time.Now @@ -18,6 +20,12 @@ func generateSerial(oldSerial uint32) uint32 { // that is smaller than the old one, we punt and increment the old number. // At no time will a serial number == 0 be returned. + if bindserial.ForcedValue != 0 { + // https://github.com/StackExchange/dnscontrol/issues/1859 + // User needs to have reproducible builds and BIND generates + return uint32(bindserial.ForcedValue & 0xFFFF) + } + original := oldSerial var newSerial uint32