Skip to content

Commit 27242ba

Browse files
Claudeborchero
andauthored
feat: Make TTL configurable for ExternalDNS integration (#218)
Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com> Co-authored-by: borchero <22455425+borchero@users.noreply.github.com> Co-authored-by: Oliver Borchert <oliver.borchert@quantco.com>
1 parent 00e957b commit 27242ba

File tree

9 files changed

+44
-6
lines changed

9 files changed

+44
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ metadata:
122122
spec:
123123
endpoints:
124124
- dnsName: www.example.com
125-
recordTTL: 300
125+
recordTTL: 300 # Default TTL, can be customized in Switchboard configuration
126126
recordType: A
127127
targets:
128128
# The target is the public (or, if unavailable, private) IP address of your Traefik

chart/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ The following lists all values that may be set when installing this chart (see
6161
| integrations.externalDNS.targetIPs | list | `[]` | The static IP addresses that created DNS records should point to. Must not be provided if the target service is set. |
6262
| integrations.externalDNS.targetService.name | string | `nil` | The name of the (Traefik) service whose IP address should be used for DNS records. |
6363
| integrations.externalDNS.targetService.namespace | string | `nil` | The namespace of the (Traefik) service whose IP address should be used for DNS records. |
64+
| integrations.externalDNS.ttl | string | `nil` | The TTL (Time To Live) for DNS records in seconds. If not specified, defaults to 300. Some DNS providers require a minimum TTL (e.g., deSEC requires 3600). |
6465
| metrics.enabled | bool | `true` | Whether the metrics endpoint should be enabled. |
6566
| metrics.port | int | `9090` | The port on which Prometheus metrics can be scraped on path `/metrics`. |
6667
| nodeSelector | object | `{}` | |

chart/templates/_config.tpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ integrations:
4848
{{ else }}
4949
{{ fail "exactly one of target service and target IPs must be set for external dns" }}
5050
{{ end }}
51+
{{ if $externalDNS.ttl }}
52+
ttl: {{ $externalDNS.ttl }}
53+
{{ end }}
5154
{{ end }}
5255
{{ end }}
5356

chart/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ integrations:
6060
name: ~
6161
# -- The namespace of the (Traefik) service whose IP address should be used for DNS records.
6262
namespace: ~
63+
# -- The TTL (Time To Live) for DNS records in seconds. If not specified, defaults to 300.
64+
# Some DNS providers require a minimum TTL (e.g., deSEC requires 3600).
65+
ttl: ~
6366

6467
metrics:
6568
# -- Whether the metrics endpoint should be enabled.

internal/config/v1/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type IntegrationConfigs struct {
5555
type ExternalDNSIntegrationConfig struct {
5656
TargetService *ServiceRef `json:"targetService,omitempty"`
5757
TargetIPs []string `json:"targetIPs,omitempty"`
58+
TTL *int64 `json:"ttl,omitempty"`
5859
}
5960

6061
// CertManagerIntegrationConfig describes the configuration for the cert-manager integration.

internal/controllers/utils.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ func integrationsFromConfig(
3232
externalDNS.TargetService.Name,
3333
externalDNS.TargetService.Namespace,
3434
),
35+
externalDNS.TTL,
3536
))
3637
} else {
3738
result = append(result, integrations.NewExternalDNS(
3839
client, switchboard.NewStaticTarget(externalDNS.TargetIPs...),
40+
externalDNS.TTL,
3941
))
4042
}
4143
}

internal/controllers/utils_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,15 @@ func TestIntegrationsFromConfig(t *testing.T) {
6464
}
6565
_, err = integrationsFromConfig(config, client)
6666
require.NotNil(t, err)
67+
68+
// Test with custom TTL configuration
69+
customTTL := int64(3600)
70+
config.Integrations.ExternalDNS = &configv1.ExternalDNSIntegrationConfig{
71+
TargetService: &configv1.ServiceRef{Name: "my-service", Namespace: "my-namespace"},
72+
TTL: &customTTL,
73+
}
74+
integrations, err = integrationsFromConfig(config, client)
75+
require.Nil(t, err)
76+
assert.Len(t, integrations, 2)
77+
assert.Equal(t, "external-dns", integrations[0].Name())
6778
}

internal/integrations/externaldns.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@ type externalDNS struct {
2222
}
2323

2424
// NewExternalDNS initializes a new external-dns integration whose created DNS endpoints target the
25-
// provided service.
26-
func NewExternalDNS(client client.Client, target switchboard.Target) Integration {
27-
return &externalDNS{client, target, 300}
25+
// provided service. If ttl is nil, a default TTL of 300 seconds is used.
26+
func NewExternalDNS(client client.Client, target switchboard.Target, ttl *int64) Integration {
27+
ttlValue := endpoint.TTL(300)
28+
if ttl != nil {
29+
ttlValue = endpoint.TTL(*ttl)
30+
}
31+
return &externalDNS{client, target, ttlValue}
2832
}
2933

3034
func (*externalDNS) Name() string {

internal/integrations/externaldns_test.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
)
1515

1616
func TestExternalDNSWatchedObject(t *testing.T) {
17-
integration := NewExternalDNS(nil, switchboard.NewServiceTarget("my-name", "my-namespace"))
17+
integration := NewExternalDNS(nil, switchboard.NewServiceTarget("my-name", "my-namespace"), nil)
1818
obj := integration.WatchedObject()
1919
assert.Equal(t, "my-name", obj.GetName())
2020
assert.Equal(t, "my-namespace", obj.GetNamespace())
@@ -32,7 +32,7 @@ func TestExternalDNSUpdateResource(t *testing.T) {
3232
owner := k8tests.DummyService("my-service", namespace, 80)
3333
err := client.Create(ctx, &owner)
3434
require.Nil(t, err)
35-
integration := NewExternalDNS(client, switchboard.NewServiceTarget(owner.Name, namespace))
35+
integration := NewExternalDNS(client, switchboard.NewServiceTarget(owner.Name, namespace), nil)
3636

3737
// No resource should be created if no hosts are provided
3838
var info IngressInfo
@@ -121,6 +121,19 @@ func TestExternalDNSRecordType(t *testing.T) {
121121
assert.Equal(t, "CNAME", integration.recordType("example.lb.identifier.amazonaws.com"))
122122
}
123123

124+
func TestExternalDNSWithCustomTTL(t *testing.T) {
125+
// Test with custom TTL
126+
customTTL := int64(3600)
127+
integration := NewExternalDNS(nil, switchboard.NewServiceTarget("my-name", "my-namespace"), &customTTL)
128+
externalDNSImpl := integration.(*externalDNS)
129+
assert.Equal(t, endpoint.TTL(3600), externalDNSImpl.ttl)
130+
131+
// Test with default TTL (nil)
132+
integration = NewExternalDNS(nil, switchboard.NewServiceTarget("my-name", "my-namespace"), nil)
133+
externalDNSImpl = integration.(*externalDNS)
134+
assert.Equal(t, endpoint.TTL(300), externalDNSImpl.ttl)
135+
}
136+
124137
//-------------------------------------------------------------------------------------------------
125138
// UTILS
126139
//-------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)