Repository: StackExchange/dnscontrol
Pull request #2442 (2023-06-17 09:07:41)

LINODE: Add Default TTL as allowed TTL
This adds `0` as an allowed TTL for Linode, which is Linode's default TTL.

I've also re-ran the integration tests and changed the `not` functions to match what is currently failing/passing.

Fixes https://github.com/StackExchange/dnscontrol/issues/2440


Patch:
diff --git a/documentation/providers/linode.md b/documentation/providers/linode.md
index 784bcf0d..de05eebb 100644
--- a/documentation/providers/linode.md
+++ b/documentation/providers/linode.md
@@ -38,8 +38,9 @@ D("example.tld", REG_NONE, DnsProvider(DSP_LINODE),
 
 ## Caveats
 Linode does not allow all TTLs, but only a specific subset of TTLs. The following TTLs are supported
-([source](https://github.com/linode/manager/blob/master/src/domains/components/SelectDNSSeconds.js)):
+([source](https://www.linode.com/docs/api/domains/#domains-list__responses)):
 
+- 0 (Default, currently equivalent to 1209600, or 14 days)
 - 300
 - 3600
 - 7200
diff --git a/providers/linode/linodeProvider.go b/providers/linode/linodeProvider.go
index bc4451b3..1e68dfc9 100644
--- a/providers/linode/linodeProvider.go
+++ b/providers/linode/linodeProvider.go
@@ -26,7 +26,10 @@ Info required in `creds.json`:
 
 */
 
+// Allowed values from the Linode API
+// https://www.linode.com/docs/api/domains/#domains-list__responses
 var allowedTTLValues = []uint32{
+	0,       // Default, currently 1209600 seconds
 	300,     // 5 minutes
 	3600,    // 1 hour
 	7200,    // 2 hours
@@ -126,8 +129,8 @@ func (api *linodeProvider) GetZoneRecords(domain string, meta map[string]string)
 func (api *linodeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
 	// Linode doesn't allow selecting an arbitrary TTL, only a set of predefined values
 	// We need to make sure we don't change it every time if it is as close as it's going to get
-	// By experimentation, Linode always rounds up. 300 -> 300, 301 -> 3600.
-	// https://github.com/linode/manager/blob/edd99dc4e1be5ab8190f243c3dbf8b830716255e/src/domains/components/SelectDNSSeconds.js#L19
+	// The documentation says that it will always round up to the next highest value: 300 -> 300, 301 -> 3600.
+	// https://www.linode.com/docs/api/domains/#domains-list__responses
 	for _, record := range dc.Records {
 		record.TTL = fixTTL(record.TTL)
 	}


Test patch:
diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go
index a7e32aa3..84ea1128 100644
--- a/integrationTest/integration_test.go
+++ b/integrationTest/integration_test.go
@@ -969,12 +969,14 @@ func makeTests(t *testing.T) []*TestGroup {
 		// weirdest edge-case we've ever seen.
 
 		testgroup("Attl",
+			not("LINODE"), // Linode does not support arbitrary TTLs: both are rounded up to 3600.
 			tc("Create Arc", ttl(a("testa", "1.1.1.1"), 333)),
 			tc("Change TTL", ttl(a("testa", "1.1.1.1"), 999)),
 		),
 
 		testgroup("TTL",
 			not("NETCUP"), // NETCUP does not support TTLs.
+			not("LINODE"), // Linode does not support arbitrary TTLs: 666 and 1000 are both rounded up to 3600.
 			tc("Start", ttl(a("@", "8.8.8.8"), 666), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
 			tc("Change a ttl", ttl(a("@", "8.8.8.8"), 1000), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
 			tc("Change single target from set", ttl(a("@", "8.8.8.8"), 1000), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
@@ -1223,7 +1225,7 @@ func makeTests(t *testing.T) []*TestGroup {
 			tc("Internationalized CNAME Target", cname("a", "ööö.com.")),
 		),
 		testgroup("IDNAs in CNAME targets",
-			not("LINODE", "CLOUDFLAREAPI"),
+			not("CLOUDFLAREAPI"),
 			// LINODE: hostname validation does not allow the target domain TLD
 			tc("IDN CNAME AND Target", cname("öoö", "ööö.企业.")),
 		),
diff --git a/providers/linode/linodeProvider_test.go b/providers/linode/linodeProvider_test.go
index 9dfff683..c4dd8236 100644
--- a/providers/linode/linodeProvider_test.go
+++ b/providers/linode/linodeProvider_test.go
@@ -6,6 +6,8 @@ func TestFixTTL(t *testing.T) {
 	for i, test := range []struct {
 		given, expected uint32
 	}{
+		{0, 0},
+		{1, 300},
 		{299, 300},
 		{300, 300},
 		{301, 3600},