dnscontrol
dnscontrol copied to clipboard
DNSControl treats a configured TTL of 0 as "not configured"
While discussing the fact that Linode's API explicitly permits and returns a TTL of 0 to represent "Default", I asked in https://github.com/StackExchange/dnscontrol/issues/2440#issuecomment-1595543504:
The question though is whether
dnscontrolhas a good way to represent "Default" in its own UX. Do any other providers have a similar concept? How do they handle a TTL of 0?
It turns out that DNSControl completely ignores any DefaultTTL(0) or TTL(0) settings, causing it to instead fall back on the global DNSControl default of 300 seconds. AFAICT the code in pkg/js/helpers.js handles things correctly, but when the JSON is parsed into Go, the resulting RecordConfig has its TTL replaced by the hard-coded global default of 300:
https://github.com/StackExchange/dnscontrol/blob/5b3bb312ea99853d1741d838d5a789cbc5eec1fb/models/record.go#L377-L379
This prevents the LINODE provider (or any other provider) from setting or preserving a TTL of 0 (as was theoretically enabled by #2442).
AFAICT the code in pkg/js/helpers.js handles things correctly,
This is probably actually just by accident. I think the core issue here is that 0 in the TTL field is being treated as "falsey" in helpers.js (while not present on the pathways I'm using, there are conditionals of the form if (r.TTL)), and the TTL field is fundamentally being treated as an optional non-zero unsigned integer, rather than an optional unsigned integer. The Go code above is just enforcing that at parse time.
Fixing this would require changing both the JavaScript and Go types to separately represent None and Some(0). On the JavaScript side that could probably be slipped in via e.g. using -1 to mean None, while on the Go side a proper Optional type would help.
These are all the spots in the Go code that map 0 to DefaultTTL:
https://github.com/StackExchange/dnscontrol/blob/5b3bb312ea99853d1741d838d5a789cbc5eec1fb/models/record.go#L377-L379
https://github.com/StackExchange/dnscontrol/blob/5b3bb312ea99853d1741d838d5a789cbc5eec1fb/pkg/normalize/validate.go#L352-L354
https://github.com/StackExchange/dnscontrol/blob/5b3bb312ea99853d1741d838d5a789cbc5eec1fb/pkg/prettyzone/prettyzone.go#L88-L90
https://github.com/StackExchange/dnscontrol/blob/5b3bb312ea99853d1741d838d5a789cbc5eec1fb/pkg/prettyzone/prettyzone.go#L103-L105
Commenting out the first two is sufficient to invert the meaining of 0 within dnscontrol preview: an explicit DefaultTTL(0) or TTL(0) gets through the LINODE provider and the corrections disappear, but by contrast all the other domains with no TTL settings no longer take up the implicit TTL of 300, and I see corrections of the form MODIFY ttl=300 -> ttl=0.
So, there are a few directions this could go:
- Implicit "provider-default TTL".
- Use that default for that provider if it exists, instead of the global DNSControl default.
- Users can explicitly mark it with
TTL("default"), but doing so is unnecessary. - If the provider exposes this default through their API via whatever sentinel value, map that to something that can be set explicitly.
- Explicit "provider-default TTL".
TTL("default")(or similar) lets users opt into the provider's default instead of the DNSControl default.TTL(0)is supported only for providers that explicitly support it via their API.
- Remove the non-zero restriction on TTL
TTL(0)is supported for any provider, and rely on each provider to raise an error if it is unsupported.- Probably still want to reject
"0m"etc as that doesn't visually map well to0being used as a default sentinel.
- Choose not to support a TTL value of 0, or any kind of "provider-default TTL", but still improve the UX of DNSControl.
- Providers that can see this value be returned from their API would need to map it to the corresponding default value inside DNSControl
- Make it an error to set
TTL(0)orDefaultTTL(0)(instead of it being silently ignored). - In
preview / push, providers would need to add extra logic to check whether a record's DNSControl-configured TTL happens to match the default, and the only correction would be to change the DSP's record from0to an explicit number; if so, suppress this correction.- Maybe also suppress this kind of correction even if something else changes, i.e. only toggle from "Default" to "explicit" via either having pushed a non-default TTL, or having done so through the provider's regular web portal.
Another useful UX thing before, or in addition to, the above: change the way colour highlighting works, to only highlight the changed parts instead of the whole MODIFY line. That would make it easier to determine what is actually being changed.
I implemented "Remove the non-zero restriction on TTL" in #2475, which AFAICT (as a non-Go developer) was the simplest approach.