• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubernetes-sigs / external-dns / 15107333227

19 May 2025 07:48AM UTC coverage: 73.518% (+0.4%) from 73.08%
15107333227

Pull #5412

github

ivankatliarchuk
chore(docs): add mkdocs-macros plugin

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
Pull Request #5412: chore(docs): add mkdocs-macros plugin

14969 of 20361 relevant lines covered (73.52%)

692.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.37
/controller/execute.go
1
/*
2
Copyright 2025 The Kubernetes Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package controller
18

19
import (
20
        "context"
21
        "fmt"
22
        "net/http"
23
        "os"
24
        "os/signal"
25
        "syscall"
26
        "time"
27

28
        "github.com/aws/aws-sdk-go-v2/service/dynamodb"
29
        "github.com/aws/aws-sdk-go-v2/service/route53"
30
        sd "github.com/aws/aws-sdk-go-v2/service/servicediscovery"
31
        "github.com/go-logr/logr"
32
        "github.com/prometheus/client_golang/prometheus/promhttp"
33
        log "github.com/sirupsen/logrus"
34
        "k8s.io/klog/v2"
35

36
        "sigs.k8s.io/external-dns/endpoint"
37
        "sigs.k8s.io/external-dns/pkg/apis/externaldns"
38
        "sigs.k8s.io/external-dns/pkg/apis/externaldns/validation"
39
        "sigs.k8s.io/external-dns/pkg/metrics"
40
        "sigs.k8s.io/external-dns/plan"
41
        "sigs.k8s.io/external-dns/provider"
42
        "sigs.k8s.io/external-dns/provider/akamai"
43
        "sigs.k8s.io/external-dns/provider/alibabacloud"
44
        "sigs.k8s.io/external-dns/provider/aws"
45
        "sigs.k8s.io/external-dns/provider/awssd"
46
        "sigs.k8s.io/external-dns/provider/azure"
47
        "sigs.k8s.io/external-dns/provider/civo"
48
        "sigs.k8s.io/external-dns/provider/cloudflare"
49
        "sigs.k8s.io/external-dns/provider/coredns"
50
        "sigs.k8s.io/external-dns/provider/digitalocean"
51
        "sigs.k8s.io/external-dns/provider/dnsimple"
52
        "sigs.k8s.io/external-dns/provider/exoscale"
53
        "sigs.k8s.io/external-dns/provider/gandi"
54
        "sigs.k8s.io/external-dns/provider/godaddy"
55
        "sigs.k8s.io/external-dns/provider/google"
56
        "sigs.k8s.io/external-dns/provider/ibmcloud"
57
        "sigs.k8s.io/external-dns/provider/inmemory"
58
        "sigs.k8s.io/external-dns/provider/linode"
59
        "sigs.k8s.io/external-dns/provider/ns1"
60
        "sigs.k8s.io/external-dns/provider/oci"
61
        "sigs.k8s.io/external-dns/provider/ovh"
62
        "sigs.k8s.io/external-dns/provider/pdns"
63
        "sigs.k8s.io/external-dns/provider/pihole"
64
        "sigs.k8s.io/external-dns/provider/plural"
65
        "sigs.k8s.io/external-dns/provider/rfc2136"
66
        "sigs.k8s.io/external-dns/provider/scaleway"
67
        "sigs.k8s.io/external-dns/provider/tencentcloud"
68
        "sigs.k8s.io/external-dns/provider/transip"
69
        "sigs.k8s.io/external-dns/provider/ultradns"
70
        "sigs.k8s.io/external-dns/provider/webhook"
71
        webhookapi "sigs.k8s.io/external-dns/provider/webhook/api"
72
        "sigs.k8s.io/external-dns/registry"
73
        "sigs.k8s.io/external-dns/source"
74
)
75

76
func Execute() {
×
77
        cfg := externaldns.NewConfig()
×
78
        if err := cfg.ParseFlags(os.Args[1:]); err != nil {
×
79
                log.Fatalf("flag parsing error: %v", err)
×
80
        }
×
81
        log.Infof("config: %s", cfg)
×
82
        if err := validation.ValidateConfig(cfg); err != nil {
×
83
                log.Fatalf("config validation failed: %v", err)
×
84
        }
×
85

86
        configureLogger(cfg)
×
87

×
88
        if cfg.DryRun {
×
89
                log.Info("running in dry-run mode. No changes to DNS records will be made.")
×
90
        }
×
91

92
        if log.GetLevel() < log.DebugLevel {
×
93
                // Klog V2 is used by k8s.io/apimachinery/pkg/labels and can throw (a lot) of irrelevant logs
×
94
                // See https://github.com/kubernetes-sigs/external-dns/issues/2348
×
95
                defer klog.ClearLogger()
×
96
                klog.SetLogger(logr.Discard())
×
97
        }
×
98

99
        log.Info(externaldns.Banner())
×
100

×
101
        ctx, cancel := context.WithCancel(context.Background())
×
102

×
103
        go serveMetrics(cfg.MetricsAddress)
×
104
        go handleSigterm(cancel)
×
105

×
106
        // Create a source.Config from the flags passed by the user.
×
107
        sourceCfg := source.NewSourceConfig(cfg)
×
108

×
109
        // Lookup all the selected sources by names and pass them the desired configuration.
×
110
        sources, err := source.ByNames(ctx, &source.SingletonClientGenerator{
×
111
                KubeConfig:   cfg.KubeConfig,
×
112
                APIServerURL: cfg.APIServerURL,
×
113
                // If update events are enabled, disable timeout.
×
114
                RequestTimeout: func() time.Duration {
×
115
                        if cfg.UpdateEvents {
×
116
                                return 0
×
117
                        }
×
118
                        return cfg.RequestTimeout
×
119
                }(),
120
        }, cfg.Sources, sourceCfg)
121
        if err != nil {
×
122
                log.Fatal(err)
×
123
        }
×
124

125
        // Filter targets
126
        targetFilter := endpoint.NewTargetNetFilterWithExclusions(cfg.TargetNetFilter, cfg.ExcludeTargetNets)
×
127

×
128
        // Combine multiple sources into a single, deduplicated source.
×
129
        endpointsSource := source.NewDedupSource(source.NewMultiSource(sources, sourceCfg.DefaultTargets))
×
130
        endpointsSource = source.NewNAT64Source(endpointsSource, cfg.NAT64Networks)
×
131
        endpointsSource = source.NewTargetFilterSource(endpointsSource, targetFilter)
×
132

×
133
        domainFilter := createDomainFilter(cfg)
×
134
        zoneNameFilter := endpoint.NewDomainFilter(cfg.ZoneNameFilter)
×
135
        zoneIDFilter := provider.NewZoneIDFilter(cfg.ZoneIDFilter)
×
136
        zoneTypeFilter := provider.NewZoneTypeFilter(cfg.AWSZoneType)
×
137
        zoneTagFilter := provider.NewZoneTagFilter(cfg.AWSZoneTagFilter)
×
138

×
139
        var p provider.Provider
×
140
        switch cfg.Provider {
×
141
        case "akamai":
×
142
                p, err = akamai.NewAkamaiProvider(
×
143
                        akamai.AkamaiConfig{
×
144
                                DomainFilter:          domainFilter,
×
145
                                ZoneIDFilter:          zoneIDFilter,
×
146
                                ServiceConsumerDomain: cfg.AkamaiServiceConsumerDomain,
×
147
                                ClientToken:           cfg.AkamaiClientToken,
×
148
                                ClientSecret:          cfg.AkamaiClientSecret,
×
149
                                AccessToken:           cfg.AkamaiAccessToken,
×
150
                                EdgercPath:            cfg.AkamaiEdgercPath,
×
151
                                EdgercSection:         cfg.AkamaiEdgercSection,
×
152
                                DryRun:                cfg.DryRun,
×
153
                        }, nil)
×
154
        case "alibabacloud":
×
155
                p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
×
156
        case "aws":
×
157
                configs := aws.CreateV2Configs(cfg)
×
158
                clients := make(map[string]aws.Route53API, len(configs))
×
159
                for profile, config := range configs {
×
160
                        clients[profile] = route53.NewFromConfig(config)
×
161
                }
×
162

163
                p, err = aws.NewAWSProvider(
×
164
                        aws.AWSConfig{
×
165
                                DomainFilter:          domainFilter,
×
166
                                ZoneIDFilter:          zoneIDFilter,
×
167
                                ZoneTypeFilter:        zoneTypeFilter,
×
168
                                ZoneTagFilter:         zoneTagFilter,
×
169
                                ZoneMatchParent:       cfg.AWSZoneMatchParent,
×
170
                                BatchChangeSize:       cfg.AWSBatchChangeSize,
×
171
                                BatchChangeSizeBytes:  cfg.AWSBatchChangeSizeBytes,
×
172
                                BatchChangeSizeValues: cfg.AWSBatchChangeSizeValues,
×
173
                                BatchChangeInterval:   cfg.AWSBatchChangeInterval,
×
174
                                EvaluateTargetHealth:  cfg.AWSEvaluateTargetHealth,
×
175
                                PreferCNAME:           cfg.AWSPreferCNAME,
×
176
                                DryRun:                cfg.DryRun,
×
177
                                ZoneCacheDuration:     cfg.AWSZoneCacheDuration,
×
178
                        },
×
179
                        clients,
×
180
                )
×
181
        case "aws-sd":
×
182
                // Check that only compatible Registry is used with AWS-SD
×
183
                if cfg.Registry != "noop" && cfg.Registry != "aws-sd" {
×
184
                        log.Infof("Registry \"%s\" cannot be used with AWS Cloud Map. Switching to \"aws-sd\".", cfg.Registry)
×
185
                        cfg.Registry = "aws-sd"
×
186
                }
×
187
                p, err = awssd.NewAWSSDProvider(domainFilter, cfg.AWSZoneType, cfg.DryRun, cfg.AWSSDServiceCleanup, cfg.TXTOwnerID, cfg.AWSSDCreateTag, sd.NewFromConfig(aws.CreateDefaultV2Config(cfg)))
×
188
        case "azure-dns", "azure":
×
189
                p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.AzureZonesCacheDuration, cfg.AzureMaxRetriesCount, cfg.DryRun)
×
190
        case "azure-private-dns":
×
191
                p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.AzureZonesCacheDuration, cfg.AzureMaxRetriesCount, cfg.DryRun)
×
192
        case "ultradns":
×
193
                p, err = ultradns.NewUltraDNSProvider(domainFilter, cfg.DryRun)
×
194
        case "civo":
×
195
                p, err = civo.NewCivoProvider(domainFilter, cfg.DryRun)
×
196
        case "cloudflare":
×
197
                p, err = cloudflare.NewCloudFlareProvider(
×
198
                        domainFilter,
×
199
                        zoneIDFilter,
×
200
                        cfg.CloudflareProxied,
×
201
                        cfg.DryRun,
×
202
                        cfg.CloudflareDNSRecordsPerPage,
×
203
                        cfg.CloudflareRegionKey,
×
204
                        cloudflare.CustomHostnamesConfig{
×
205
                                Enabled:              cfg.CloudflareCustomHostnames,
×
206
                                MinTLSVersion:        cfg.CloudflareCustomHostnamesMinTLSVersion,
×
207
                                CertificateAuthority: cfg.CloudflareCustomHostnamesCertificateAuthority,
×
208
                        })
×
209
        case "google":
×
210
                p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.GoogleZoneVisibility, cfg.DryRun)
×
211
        case "digitalocean":
×
212
                p, err = digitalocean.NewDigitalOceanProvider(ctx, domainFilter, cfg.DryRun, cfg.DigitalOceanAPIPageSize)
×
213
        case "ovh":
×
214
                p, err = ovh.NewOVHProvider(ctx, domainFilter, cfg.OVHEndpoint, cfg.OVHApiRateLimit, cfg.OVHEnableCNAMERelative, cfg.DryRun)
×
215
        case "linode":
×
216
                p, err = linode.NewLinodeProvider(domainFilter, cfg.DryRun)
×
217
        case "dnsimple":
×
218
                p, err = dnsimple.NewDnsimpleProvider(domainFilter, zoneIDFilter, cfg.DryRun)
×
219
        case "coredns", "skydns":
×
220
                p, err = coredns.NewCoreDNSProvider(domainFilter, cfg.CoreDNSPrefix, cfg.DryRun)
×
221
        case "exoscale":
×
222
                p, err = exoscale.NewExoscaleProvider(
×
223
                        cfg.ExoscaleAPIEnvironment,
×
224
                        cfg.ExoscaleAPIZone,
×
225
                        cfg.ExoscaleAPIKey,
×
226
                        cfg.ExoscaleAPISecret,
×
227
                        cfg.DryRun,
×
228
                        exoscale.ExoscaleWithDomain(domainFilter),
×
229
                        exoscale.ExoscaleWithLogging(),
×
230
                )
×
231
        case "inmemory":
×
232
                p, err = inmemory.NewInMemoryProvider(inmemory.InMemoryInitZones(cfg.InMemoryZones), inmemory.InMemoryWithDomain(domainFilter), inmemory.InMemoryWithLogging()), nil
×
233
        case "pdns":
×
234
                p, err = pdns.NewPDNSProvider(
×
235
                        ctx,
×
236
                        pdns.PDNSConfig{
×
237
                                DomainFilter: domainFilter,
×
238
                                DryRun:       cfg.DryRun,
×
239
                                Server:       cfg.PDNSServer,
×
240
                                ServerID:     cfg.PDNSServerID,
×
241
                                APIKey:       cfg.PDNSAPIKey,
×
242
                                TLSConfig: pdns.TLSConfig{
×
243
                                        SkipTLSVerify:         cfg.PDNSSkipTLSVerify,
×
244
                                        CAFilePath:            cfg.TLSCA,
×
245
                                        ClientCertFilePath:    cfg.TLSClientCert,
×
246
                                        ClientCertKeyFilePath: cfg.TLSClientCertKey,
×
247
                                },
×
248
                        },
×
249
                )
×
250
        case "oci":
×
251
                var config *oci.OCIConfig
×
252
                // if the instance-principals flag was set, and a compartment OCID was provided, then ignore the
×
253
                // OCI config file, and provide a config that uses instance principal authentication.
×
254
                if cfg.OCIAuthInstancePrincipal {
×
255
                        if len(cfg.OCICompartmentOCID) == 0 {
×
256
                                err = fmt.Errorf("instance principal authentication requested, but no compartment OCID provided")
×
257
                        } else {
×
258
                                authConfig := oci.OCIAuthConfig{UseInstancePrincipal: true}
×
259
                                config = &oci.OCIConfig{Auth: authConfig, CompartmentID: cfg.OCICompartmentOCID}
×
260
                        }
×
261
                } else {
×
262
                        config, err = oci.LoadOCIConfig(cfg.OCIConfigFile)
×
263
                }
×
264
                config.ZoneCacheDuration = cfg.OCIZoneCacheDuration
×
265
                if err == nil {
×
266
                        p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.OCIZoneScope, cfg.DryRun)
×
267
                }
×
268
        case "rfc2136":
×
269
                tlsConfig := rfc2136.TLSConfig{
×
270
                        UseTLS:                cfg.RFC2136UseTLS,
×
271
                        SkipTLSVerify:         cfg.RFC2136SkipTLSVerify,
×
272
                        CAFilePath:            cfg.TLSCA,
×
273
                        ClientCertFilePath:    cfg.TLSClientCert,
×
274
                        ClientCertKeyFilePath: cfg.TLSClientCertKey,
×
275
                }
×
276
                p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136CreatePTR, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, cfg.RFC2136KerberosRealm, cfg.RFC2136BatchChangeSize, tlsConfig, cfg.RFC2136LoadBalancingStrategy, nil)
×
277
        case "ns1":
×
278
                p, err = ns1.NewNS1Provider(
×
279
                        ns1.NS1Config{
×
280
                                DomainFilter:  domainFilter,
×
281
                                ZoneIDFilter:  zoneIDFilter,
×
282
                                NS1Endpoint:   cfg.NS1Endpoint,
×
283
                                NS1IgnoreSSL:  cfg.NS1IgnoreSSL,
×
284
                                DryRun:        cfg.DryRun,
×
285
                                MinTTLSeconds: cfg.NS1MinTTLSeconds,
×
286
                        },
×
287
                )
×
288
        case "transip":
×
289
                p, err = transip.NewTransIPProvider(cfg.TransIPAccountName, cfg.TransIPPrivateKeyFile, domainFilter, cfg.DryRun)
×
290
        case "scaleway":
×
291
                p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun)
×
292
        case "godaddy":
×
293
                p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyTTL, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyOTE, cfg.DryRun)
×
294
        case "gandi":
×
295
                p, err = gandi.NewGandiProvider(ctx, domainFilter, cfg.DryRun)
×
296
        case "pihole":
×
297
                p, err = pihole.NewPiholeProvider(
×
298
                        pihole.PiholeConfig{
×
299
                                Server:                cfg.PiholeServer,
×
300
                                Password:              cfg.PiholePassword,
×
301
                                TLSInsecureSkipVerify: cfg.PiholeTLSInsecureSkipVerify,
×
302
                                DomainFilter:          domainFilter,
×
303
                                DryRun:                cfg.DryRun,
×
304
                                APIVersion:            cfg.PiholeApiVersion,
×
305
                        },
×
306
                )
×
307
        case "ibmcloud":
×
308
                p, err = ibmcloud.NewIBMCloudProvider(cfg.IBMCloudConfigFile, domainFilter, zoneIDFilter, endpointsSource, cfg.IBMCloudProxied, cfg.DryRun)
×
309
        case "plural":
×
310
                p, err = plural.NewPluralProvider(cfg.PluralCluster, cfg.PluralProvider)
×
311
        case "tencentcloud":
×
312
                p, err = tencentcloud.NewTencentCloudProvider(domainFilter, zoneIDFilter, cfg.TencentCloudConfigFile, cfg.TencentCloudZoneType, cfg.DryRun)
×
313
        case "webhook":
×
314
                p, err = webhook.NewWebhookProvider(cfg.WebhookProviderURL)
×
315
        default:
×
316
                log.Fatalf("unknown dns provider: %s", cfg.Provider)
×
317
        }
×
318
        if err != nil {
×
319
                log.Fatal(err)
×
320
        }
321

×
322
        if cfg.WebhookServer {
×
323
                webhookapi.StartHTTPApi(p, nil, cfg.WebhookProviderReadTimeout, cfg.WebhookProviderWriteTimeout, "127.0.0.1:8888")
×
324
                os.Exit(0)
325
        }
×
326

×
327
        if cfg.ProviderCacheTime > 0 {
×
328
                p = provider.NewCachedProvider(
×
329
                        p,
330
                        cfg.ProviderCacheTime,
×
331
                )
×
332
        }
×
333

×
334
        reg, err := selectRegistry(cfg, p)
×
335
        if err != nil {
×
336
                log.Fatal(err)
337
        }
×
338

×
339
        policy, exists := plan.Policies[cfg.Policy]
×
340
        if !exists {
×
341
                log.Fatalf("unknown policy: %s", cfg.Policy)
342
        }
×
343

×
344
        ctrl := Controller{
×
345
                Source:               endpointsSource,
×
346
                Registry:             reg,
347
                Policy:               policy,
×
348
                Interval:             cfg.Interval,
×
349
                DomainFilter:         domainFilter,
×
350
                ManagedRecordTypes:   cfg.ManagedDNSRecordTypes,
×
351
                ExcludeRecordTypes:   cfg.ExcludeDNSRecordTypes,
×
352
                MinEventSyncInterval: cfg.MinEventSyncInterval,
×
353
        }
×
354

×
355
        if cfg.Once {
×
356
                err := ctrl.RunOnce(ctx)
×
357
                if err != nil {
×
358
                        log.Fatal(err)
×
359
                }
×
360

×
361
                os.Exit(0)
×
362
        }
×
363

364
        if cfg.UpdateEvents {
×
365
                // Add RunOnce as the handler function that will be called when ingress/service sources have changed.
366
                // Note that k8s Informers will perform an initial list operation, which results in the handler
367
                // function initially being called for every Service/Ingress that exists
×
368
                ctrl.Source.AddEventHandler(ctx, func() { ctrl.ScheduleRunOnce(time.Now()) })
×
369
        }
×
370

×
371
        ctrl.ScheduleRunOnce(time.Now())
×
372
        ctrl.Run(ctx)
373
}
374

×
375
// This function configures the logger format and level based on the provided configuration.
×
376
func configureLogger(cfg *externaldns.Config) {
377
        if cfg.LogFormat == "json" {
378
                log.SetFormatter(&log.JSONFormatter{})
379
        }
3✔
380
        ll, err := log.ParseLevel(cfg.LogLevel)
4✔
381
        if err != nil {
1✔
382
                log.Fatalf("failed to parse log level: %v", err)
1✔
383
        }
3✔
384
        log.SetLevel(ll)
4✔
385
}
1✔
386

1✔
387
// selectRegistry selects the appropriate registry implementation based on the configuration in cfg.
3✔
388
// It initializes and returns a registry along with any error encountered during setup.
389
// Supported registry types include: dynamodb, noop, txt, and aws-sd.
390
func selectRegistry(cfg *externaldns.Config, p provider.Provider) (registry.Registry, error) {
391
        var r registry.Registry
392
        var err error
393
        switch cfg.Registry {
5✔
394
        case "dynamodb":
5✔
395
                var dynamodbOpts []func(*dynamodb.Options)
5✔
396
                if cfg.AWSDynamoDBRegion != "" {
5✔
397
                        dynamodbOpts = []func(*dynamodb.Options){
1✔
398
                                func(opts *dynamodb.Options) {
1✔
399
                                        opts.Region = cfg.AWSDynamoDBRegion
2✔
400
                                },
1✔
401
                        }
2✔
402
                }
1✔
403
                r, err = registry.NewDynamoDBRegistry(p, cfg.TXTOwnerID, dynamodb.NewFromConfig(aws.CreateDefaultV2Config(cfg), dynamodbOpts...), cfg.AWSDynamoDBTable, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, []byte(cfg.TXTEncryptAESKey), cfg.TXTCacheInterval)
1✔
404
        case "noop":
405
                r, err = registry.NewNoopRegistry(p)
406
        case "txt":
1✔
407
                r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, cfg.TXTEncryptEnabled, []byte(cfg.TXTEncryptAESKey), cfg.TXTNewFormatOnly)
1✔
408
        case "aws-sd":
1✔
409
                r, err = registry.NewAWSSDRegistry(p, cfg.TXTOwnerID)
1✔
410
        default:
1✔
411
                log.Fatalf("unknown registry: %s", cfg.Registry)
1✔
412
        }
1✔
413
        return r, err
1✔
414
}
1✔
415

416
// RegexDomainFilter overrides DomainFilter
5✔
417
func createDomainFilter(cfg *externaldns.Config) endpoint.DomainFilter {
418
        if cfg.RegexDomainFilter != nil && cfg.RegexDomainFilter.String() != "" {
419
                return endpoint.NewRegexDomainFilter(cfg.RegexDomainFilter, cfg.RegexDomainExclusion)
420
        } else {
5✔
421
                return endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains)
7✔
422
        }
2✔
423
}
5✔
424

3✔
425
// handleSigterm listens for a SIGTERM signal and triggers the provided cancel function
3✔
426
// to gracefully terminate the application. It logs a message when the signal is received.
427
func handleSigterm(cancel func()) {
428
        signals := make(chan os.Signal, 1)
429
        signal.Notify(signals, syscall.SIGTERM)
430
        <-signals
1✔
431
        log.Info("Received SIGTERM. Terminating...")
1✔
432
        cancel()
1✔
433
}
1✔
434

1✔
435
// serveMetrics starts an HTTP server that serves health and metrics endpoints.
1✔
436
// The /healthz endpoint returns a 200 OK status to indicate the service is healthy.
1✔
437
// The /metrics endpoint serves Prometheus metrics.
438
// The server listens on the specified address and logs debug information about the endpoints.
439
func serveMetrics(address string) {
440
        http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
441
                w.WriteHeader(http.StatusOK)
442
                _, _ = w.Write([]byte("OK"))
1✔
443
        })
2✔
444

1✔
445
        log.Debugf("serving 'healthz' on 'localhost:%s/healthz'", address)
1✔
446
        log.Debugf("serving 'metrics' on 'localhost:%s/metrics'", address)
1✔
447
        log.Debugf("registered '%d' metrics", len(metrics.RegisterMetric.Metrics))
448

1✔
449
        http.Handle("/metrics", promhttp.Handler())
1✔
450

1✔
451
        log.Fatal(http.ListenAndServe(address, nil))
1✔
452
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc