dnscontrol icon indicating copy to clipboard operation
dnscontrol copied to clipboard

DNSControl treats a configured TTL of 0 as "not configured"

Open str4d opened this issue 2 years ago • 5 comments
trafficstars

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 dnscontrol has 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).

str4d avatar Jun 17 '23 21:06 str4d

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.

str4d avatar Jun 17 '23 22:06 str4d

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.

str4d avatar Jun 18 '23 00:06 str4d

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 to 0 being 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) or DefaultTTL(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 from 0 to 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.

str4d avatar Jun 18 '23 00:06 str4d

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.

str4d avatar Jun 18 '23 00:06 str4d

I implemented "Remove the non-zero restriction on TTL" in #2475, which AFAICT (as a non-Go developer) was the simplest approach.

str4d avatar Jul 10 '23 02:07 str4d