mirror of
				https://github.com/kubernetes-sigs/external-dns.git
				synced 2025-10-31 10:41:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			403 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2017 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"os/signal"
 | |
| 	"syscall"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/prometheus/client_golang/prometheus/promhttp"
 | |
| 	log "github.com/sirupsen/logrus"
 | |
| 	"k8s.io/apimachinery/pkg/labels"
 | |
| 	_ "k8s.io/client-go/plugin/pkg/client/auth"
 | |
| 
 | |
| 	"sigs.k8s.io/external-dns/controller"
 | |
| 	"sigs.k8s.io/external-dns/endpoint"
 | |
| 	"sigs.k8s.io/external-dns/pkg/apis/externaldns"
 | |
| 	"sigs.k8s.io/external-dns/pkg/apis/externaldns/validation"
 | |
| 	"sigs.k8s.io/external-dns/plan"
 | |
| 	"sigs.k8s.io/external-dns/provider"
 | |
| 	"sigs.k8s.io/external-dns/provider/akamai"
 | |
| 	"sigs.k8s.io/external-dns/provider/alibabacloud"
 | |
| 	"sigs.k8s.io/external-dns/provider/aws"
 | |
| 	"sigs.k8s.io/external-dns/provider/awssd"
 | |
| 	"sigs.k8s.io/external-dns/provider/azure"
 | |
| 	"sigs.k8s.io/external-dns/provider/bluecat"
 | |
| 	"sigs.k8s.io/external-dns/provider/cloudflare"
 | |
| 	"sigs.k8s.io/external-dns/provider/coredns"
 | |
| 	"sigs.k8s.io/external-dns/provider/designate"
 | |
| 	"sigs.k8s.io/external-dns/provider/digitalocean"
 | |
| 	"sigs.k8s.io/external-dns/provider/dnsimple"
 | |
| 	"sigs.k8s.io/external-dns/provider/dyn"
 | |
| 	"sigs.k8s.io/external-dns/provider/exoscale"
 | |
| 	"sigs.k8s.io/external-dns/provider/gandi"
 | |
| 	"sigs.k8s.io/external-dns/provider/godaddy"
 | |
| 	"sigs.k8s.io/external-dns/provider/google"
 | |
| 	"sigs.k8s.io/external-dns/provider/infoblox"
 | |
| 	"sigs.k8s.io/external-dns/provider/inmemory"
 | |
| 	"sigs.k8s.io/external-dns/provider/linode"
 | |
| 	"sigs.k8s.io/external-dns/provider/ns1"
 | |
| 	"sigs.k8s.io/external-dns/provider/oci"
 | |
| 	"sigs.k8s.io/external-dns/provider/ovh"
 | |
| 	"sigs.k8s.io/external-dns/provider/pdns"
 | |
| 	"sigs.k8s.io/external-dns/provider/rcode0"
 | |
| 	"sigs.k8s.io/external-dns/provider/rdns"
 | |
| 	"sigs.k8s.io/external-dns/provider/rfc2136"
 | |
| 	"sigs.k8s.io/external-dns/provider/safedns"
 | |
| 	"sigs.k8s.io/external-dns/provider/scaleway"
 | |
| 	"sigs.k8s.io/external-dns/provider/transip"
 | |
| 	"sigs.k8s.io/external-dns/provider/ultradns"
 | |
| 	"sigs.k8s.io/external-dns/provider/vinyldns"
 | |
| 	"sigs.k8s.io/external-dns/provider/vultr"
 | |
| 	"sigs.k8s.io/external-dns/registry"
 | |
| 	"sigs.k8s.io/external-dns/source"
 | |
| )
 | |
| 
 | |
| func main() {
 | |
| 	cfg := externaldns.NewConfig()
 | |
| 	if err := cfg.ParseFlags(os.Args[1:]); err != nil {
 | |
| 		log.Fatalf("flag parsing error: %v", err)
 | |
| 	}
 | |
| 	log.Infof("config: %s", cfg)
 | |
| 
 | |
| 	if err := validation.ValidateConfig(cfg); err != nil {
 | |
| 		log.Fatalf("config validation failed: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if cfg.LogFormat == "json" {
 | |
| 		log.SetFormatter(&log.JSONFormatter{})
 | |
| 	}
 | |
| 	if cfg.DryRun {
 | |
| 		log.Info("running in dry-run mode. No changes to DNS records will be made.")
 | |
| 	}
 | |
| 
 | |
| 	ll, err := log.ParseLevel(cfg.LogLevel)
 | |
| 	if err != nil {
 | |
| 		log.Fatalf("failed to parse log level: %v", err)
 | |
| 	}
 | |
| 	log.SetLevel(ll)
 | |
| 
 | |
| 	ctx, cancel := context.WithCancel(context.Background())
 | |
| 
 | |
| 	go serveMetrics(cfg.MetricsAddress)
 | |
| 	go handleSigterm(cancel)
 | |
| 
 | |
| 	// error is explicitly ignored because the filter is already validated in validation.ValidateConfig
 | |
| 	labelSelector, _ := labels.Parse(cfg.LabelFilter)
 | |
| 
 | |
| 	// Create a source.Config from the flags passed by the user.
 | |
| 	sourceCfg := &source.Config{
 | |
| 		Namespace:                      cfg.Namespace,
 | |
| 		AnnotationFilter:               cfg.AnnotationFilter,
 | |
| 		LabelFilter:                    labelSelector,
 | |
| 		FQDNTemplate:                   cfg.FQDNTemplate,
 | |
| 		CombineFQDNAndAnnotation:       cfg.CombineFQDNAndAnnotation,
 | |
| 		IgnoreHostnameAnnotation:       cfg.IgnoreHostnameAnnotation,
 | |
| 		IgnoreIngressTLSSpec:           cfg.IgnoreIngressTLSSpec,
 | |
| 		IgnoreIngressRulesSpec:         cfg.IgnoreIngressRulesSpec,
 | |
| 		Compatibility:                  cfg.Compatibility,
 | |
| 		PublishInternal:                cfg.PublishInternal,
 | |
| 		PublishHostIP:                  cfg.PublishHostIP,
 | |
| 		AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses,
 | |
| 		ConnectorServer:                cfg.ConnectorSourceServer,
 | |
| 		CRDSourceAPIVersion:            cfg.CRDSourceAPIVersion,
 | |
| 		CRDSourceKind:                  cfg.CRDSourceKind,
 | |
| 		KubeConfig:                     cfg.KubeConfig,
 | |
| 		APIServerURL:                   cfg.APIServerURL,
 | |
| 		ServiceTypeFilter:              cfg.ServiceTypeFilter,
 | |
| 		CFAPIEndpoint:                  cfg.CFAPIEndpoint,
 | |
| 		CFUsername:                     cfg.CFUsername,
 | |
| 		CFPassword:                     cfg.CFPassword,
 | |
| 		ContourLoadBalancerService:     cfg.ContourLoadBalancerService,
 | |
| 		GlooNamespace:                  cfg.GlooNamespace,
 | |
| 		SkipperRouteGroupVersion:       cfg.SkipperRouteGroupVersion,
 | |
| 		RequestTimeout:                 cfg.RequestTimeout,
 | |
| 		DefaultTargets:                 cfg.DefaultTargets,
 | |
| 		OCPRouterName:                  cfg.OCPRouterName,
 | |
| 	}
 | |
| 
 | |
| 	// Lookup all the selected sources by names and pass them the desired configuration.
 | |
| 	sources, err := source.ByNames(ctx, &source.SingletonClientGenerator{
 | |
| 		KubeConfig:   cfg.KubeConfig,
 | |
| 		APIServerURL: cfg.APIServerURL,
 | |
| 		// If update events are enabled, disable timeout.
 | |
| 		RequestTimeout: func() time.Duration {
 | |
| 			if cfg.UpdateEvents {
 | |
| 				return 0
 | |
| 			}
 | |
| 			return cfg.RequestTimeout
 | |
| 		}(),
 | |
| 	}, cfg.Sources, sourceCfg)
 | |
| 	if err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// Combine multiple sources into a single, deduplicated source.
 | |
| 	endpointsSource := source.NewDedupSource(source.NewMultiSource(sources, sourceCfg.DefaultTargets))
 | |
| 
 | |
| 	// RegexDomainFilter overrides DomainFilter
 | |
| 	var domainFilter endpoint.DomainFilter
 | |
| 	if cfg.RegexDomainFilter.String() != "" {
 | |
| 		domainFilter = endpoint.NewRegexDomainFilter(cfg.RegexDomainFilter, cfg.RegexDomainExclusion)
 | |
| 	} else {
 | |
| 		domainFilter = endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains)
 | |
| 	}
 | |
| 	zoneNameFilter := endpoint.NewDomainFilter(cfg.ZoneNameFilter)
 | |
| 	zoneIDFilter := provider.NewZoneIDFilter(cfg.ZoneIDFilter)
 | |
| 	zoneTypeFilter := provider.NewZoneTypeFilter(cfg.AWSZoneType)
 | |
| 	zoneTagFilter := provider.NewZoneTagFilter(cfg.AWSZoneTagFilter)
 | |
| 
 | |
| 	var p provider.Provider
 | |
| 	switch cfg.Provider {
 | |
| 	case "akamai":
 | |
| 		p, err = akamai.NewAkamaiProvider(
 | |
| 			akamai.AkamaiConfig{
 | |
| 				DomainFilter:          domainFilter,
 | |
| 				ZoneIDFilter:          zoneIDFilter,
 | |
| 				ServiceConsumerDomain: cfg.AkamaiServiceConsumerDomain,
 | |
| 				ClientToken:           cfg.AkamaiClientToken,
 | |
| 				ClientSecret:          cfg.AkamaiClientSecret,
 | |
| 				AccessToken:           cfg.AkamaiAccessToken,
 | |
| 				EdgercPath:            cfg.AkamaiEdgercPath,
 | |
| 				EdgercSection:         cfg.AkamaiEdgercSection,
 | |
| 				DryRun:                cfg.DryRun,
 | |
| 			}, nil)
 | |
| 	case "alibabacloud":
 | |
| 		p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
 | |
| 	case "aws":
 | |
| 		p, err = aws.NewAWSProvider(
 | |
| 			aws.AWSConfig{
 | |
| 				DomainFilter:         domainFilter,
 | |
| 				ZoneIDFilter:         zoneIDFilter,
 | |
| 				ZoneTypeFilter:       zoneTypeFilter,
 | |
| 				ZoneTagFilter:        zoneTagFilter,
 | |
| 				BatchChangeSize:      cfg.AWSBatchChangeSize,
 | |
| 				BatchChangeInterval:  cfg.AWSBatchChangeInterval,
 | |
| 				EvaluateTargetHealth: cfg.AWSEvaluateTargetHealth,
 | |
| 				AssumeRole:           cfg.AWSAssumeRole,
 | |
| 				APIRetries:           cfg.AWSAPIRetries,
 | |
| 				PreferCNAME:          cfg.AWSPreferCNAME,
 | |
| 				DryRun:               cfg.DryRun,
 | |
| 				ZoneCacheDuration:    cfg.AWSZoneCacheDuration,
 | |
| 			},
 | |
| 		)
 | |
| 	case "aws-sd":
 | |
| 		// Check that only compatible Registry is used with AWS-SD
 | |
| 		if cfg.Registry != "noop" && cfg.Registry != "aws-sd" {
 | |
| 			log.Infof("Registry \"%s\" cannot be used with AWS Cloud Map. Switching to \"aws-sd\".", cfg.Registry)
 | |
| 			cfg.Registry = "aws-sd"
 | |
| 		}
 | |
| 		p, err = awssd.NewAWSSDProvider(domainFilter, cfg.AWSZoneType, cfg.AWSAssumeRole, cfg.DryRun, cfg.AWSSDServiceCleanup, cfg.TXTOwnerID)
 | |
| 	case "azure-dns", "azure":
 | |
| 		p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun)
 | |
| 	case "azure-private-dns":
 | |
| 		p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun)
 | |
| 	case "bluecat":
 | |
| 		p, err = bluecat.NewBluecatProvider(cfg.BluecatConfigFile, cfg.BluecatDNSConfiguration, cfg.BluecatDNSServerName, cfg.BluecatDNSDeployType, cfg.BluecatDNSView, cfg.BluecatGatewayHost, cfg.BluecatRootZone, domainFilter, zoneIDFilter, cfg.DryRun, cfg.BluecatSkipTLSVerify)
 | |
| 	case "vinyldns":
 | |
| 		p, err = vinyldns.NewVinylDNSProvider(domainFilter, zoneIDFilter, cfg.DryRun)
 | |
| 	case "vultr":
 | |
| 		p, err = vultr.NewVultrProvider(ctx, domainFilter, cfg.DryRun)
 | |
| 	case "ultradns":
 | |
| 		p, err = ultradns.NewUltraDNSProvider(domainFilter, cfg.DryRun)
 | |
| 	case "cloudflare":
 | |
| 		p, err = cloudflare.NewCloudFlareProvider(domainFilter, zoneIDFilter, cfg.CloudflareZonesPerPage, cfg.CloudflareProxied, cfg.DryRun)
 | |
| 	case "rcodezero":
 | |
| 		p, err = rcode0.NewRcodeZeroProvider(domainFilter, cfg.DryRun, cfg.RcodezeroTXTEncrypt)
 | |
| 	case "google":
 | |
| 		p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.GoogleZoneVisibility, cfg.DryRun)
 | |
| 	case "digitalocean":
 | |
| 		p, err = digitalocean.NewDigitalOceanProvider(ctx, domainFilter, cfg.DryRun, cfg.DigitalOceanAPIPageSize)
 | |
| 	case "ovh":
 | |
| 		p, err = ovh.NewOVHProvider(ctx, domainFilter, cfg.OVHEndpoint, cfg.OVHApiRateLimit, cfg.DryRun)
 | |
| 	case "linode":
 | |
| 		p, err = linode.NewLinodeProvider(domainFilter, cfg.DryRun, externaldns.Version)
 | |
| 	case "dnsimple":
 | |
| 		p, err = dnsimple.NewDnsimpleProvider(domainFilter, zoneIDFilter, cfg.DryRun)
 | |
| 	case "infoblox":
 | |
| 		p, err = infoblox.NewInfobloxProvider(
 | |
| 			infoblox.InfobloxConfig{
 | |
| 				DomainFilter:  domainFilter,
 | |
| 				ZoneIDFilter:  zoneIDFilter,
 | |
| 				Host:          cfg.InfobloxGridHost,
 | |
| 				Port:          cfg.InfobloxWapiPort,
 | |
| 				Username:      cfg.InfobloxWapiUsername,
 | |
| 				Password:      cfg.InfobloxWapiPassword,
 | |
| 				Version:       cfg.InfobloxWapiVersion,
 | |
| 				SSLVerify:     cfg.InfobloxSSLVerify,
 | |
| 				View:          cfg.InfobloxView,
 | |
| 				MaxResults:    cfg.InfobloxMaxResults,
 | |
| 				DryRun:        cfg.DryRun,
 | |
| 				FQDNRexEx:     cfg.InfobloxFQDNRegEx,
 | |
| 				CreatePTR:     cfg.InfobloxCreatePTR,
 | |
| 				CacheDuration: cfg.InfobloxCacheDuration,
 | |
| 			},
 | |
| 		)
 | |
| 	case "dyn":
 | |
| 		p, err = dyn.NewDynProvider(
 | |
| 			dyn.DynConfig{
 | |
| 				DomainFilter:  domainFilter,
 | |
| 				ZoneIDFilter:  zoneIDFilter,
 | |
| 				DryRun:        cfg.DryRun,
 | |
| 				CustomerName:  cfg.DynCustomerName,
 | |
| 				Username:      cfg.DynUsername,
 | |
| 				Password:      cfg.DynPassword,
 | |
| 				MinTTLSeconds: cfg.DynMinTTLSeconds,
 | |
| 				AppVersion:    externaldns.Version,
 | |
| 			},
 | |
| 		)
 | |
| 	case "coredns", "skydns":
 | |
| 		p, err = coredns.NewCoreDNSProvider(domainFilter, cfg.CoreDNSPrefix, cfg.DryRun)
 | |
| 	case "rdns":
 | |
| 		p, err = rdns.NewRDNSProvider(
 | |
| 			rdns.RDNSConfig{
 | |
| 				DomainFilter: domainFilter,
 | |
| 				DryRun:       cfg.DryRun,
 | |
| 			},
 | |
| 		)
 | |
| 	case "exoscale":
 | |
| 		p, err = exoscale.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, cfg.DryRun, exoscale.ExoscaleWithDomain(domainFilter), exoscale.ExoscaleWithLogging()), nil
 | |
| 	case "inmemory":
 | |
| 		p, err = inmemory.NewInMemoryProvider(inmemory.InMemoryInitZones(cfg.InMemoryZones), inmemory.InMemoryWithDomain(domainFilter), inmemory.InMemoryWithLogging()), nil
 | |
| 	case "designate":
 | |
| 		p, err = designate.NewDesignateProvider(domainFilter, cfg.DryRun)
 | |
| 	case "pdns":
 | |
| 		p, err = pdns.NewPDNSProvider(
 | |
| 			ctx,
 | |
| 			pdns.PDNSConfig{
 | |
| 				DomainFilter: domainFilter,
 | |
| 				DryRun:       cfg.DryRun,
 | |
| 				Server:       cfg.PDNSServer,
 | |
| 				APIKey:       cfg.PDNSAPIKey,
 | |
| 				TLSConfig: pdns.TLSConfig{
 | |
| 					TLSEnabled:            cfg.PDNSTLSEnabled,
 | |
| 					CAFilePath:            cfg.TLSCA,
 | |
| 					ClientCertFilePath:    cfg.TLSClientCert,
 | |
| 					ClientCertKeyFilePath: cfg.TLSClientCertKey,
 | |
| 				},
 | |
| 			},
 | |
| 		)
 | |
| 	case "oci":
 | |
| 		var config *oci.OCIConfig
 | |
| 		config, err = oci.LoadOCIConfig(cfg.OCIConfigFile)
 | |
| 		if err == nil {
 | |
| 			p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun)
 | |
| 		}
 | |
| 	case "rfc2136":
 | |
| 		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.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, cfg.RFC2136KerberosRealm, cfg.RFC2136BatchChangeSize, nil)
 | |
| 	case "ns1":
 | |
| 		p, err = ns1.NewNS1Provider(
 | |
| 			ns1.NS1Config{
 | |
| 				DomainFilter:  domainFilter,
 | |
| 				ZoneIDFilter:  zoneIDFilter,
 | |
| 				NS1Endpoint:   cfg.NS1Endpoint,
 | |
| 				NS1IgnoreSSL:  cfg.NS1IgnoreSSL,
 | |
| 				DryRun:        cfg.DryRun,
 | |
| 				MinTTLSeconds: cfg.NS1MinTTLSeconds,
 | |
| 			},
 | |
| 		)
 | |
| 	case "transip":
 | |
| 		p, err = transip.NewTransIPProvider(cfg.TransIPAccountName, cfg.TransIPPrivateKeyFile, domainFilter, cfg.DryRun)
 | |
| 	case "scaleway":
 | |
| 		p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun)
 | |
| 	case "godaddy":
 | |
| 		p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyTTL, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyOTE, cfg.DryRun)
 | |
| 	case "gandi":
 | |
| 		p, err = gandi.NewGandiProvider(ctx, domainFilter, cfg.DryRun)
 | |
| 	case "safedns":
 | |
| 		p, err = safedns.NewSafeDNSProvider(domainFilter, cfg.DryRun)
 | |
| 	default:
 | |
| 		log.Fatalf("unknown dns provider: %s", cfg.Provider)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	var r registry.Registry
 | |
| 	switch cfg.Registry {
 | |
| 	case "noop":
 | |
| 		r, err = registry.NewNoopRegistry(p)
 | |
| 	case "txt":
 | |
| 		r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement)
 | |
| 	case "aws-sd":
 | |
| 		r, err = registry.NewAWSSDRegistry(p.(*awssd.AWSSDProvider), cfg.TXTOwnerID)
 | |
| 	default:
 | |
| 		log.Fatalf("unknown registry: %s", cfg.Registry)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	policy, exists := plan.Policies[cfg.Policy]
 | |
| 	if !exists {
 | |
| 		log.Fatalf("unknown policy: %s", cfg.Policy)
 | |
| 	}
 | |
| 
 | |
| 	ctrl := controller.Controller{
 | |
| 		Source:               endpointsSource,
 | |
| 		Registry:             r,
 | |
| 		Policy:               policy,
 | |
| 		Interval:             cfg.Interval,
 | |
| 		DomainFilter:         domainFilter,
 | |
| 		ManagedRecordTypes:   cfg.ManagedDNSRecordTypes,
 | |
| 		MinEventSyncInterval: cfg.MinEventSyncInterval,
 | |
| 	}
 | |
| 
 | |
| 	if cfg.Once {
 | |
| 		err := ctrl.RunOnce(ctx)
 | |
| 		if err != nil {
 | |
| 			log.Fatal(err)
 | |
| 		}
 | |
| 
 | |
| 		os.Exit(0)
 | |
| 	}
 | |
| 
 | |
| 	if cfg.UpdateEvents {
 | |
| 		// Add RunOnce as the handler function that will be called when ingress/service sources have changed.
 | |
| 		// Note that k8s Informers will perform an initial list operation, which results in the handler
 | |
| 		// function initially being called for every Service/Ingress that exists
 | |
| 		ctrl.Source.AddEventHandler(ctx, func() { ctrl.ScheduleRunOnce(time.Now()) })
 | |
| 	}
 | |
| 
 | |
| 	ctrl.ScheduleRunOnce(time.Now())
 | |
| 	ctrl.Run(ctx)
 | |
| }
 | |
| 
 | |
| func handleSigterm(cancel func()) {
 | |
| 	signals := make(chan os.Signal, 1)
 | |
| 	signal.Notify(signals, syscall.SIGTERM)
 | |
| 	<-signals
 | |
| 	log.Info("Received SIGTERM. Terminating...")
 | |
| 	cancel()
 | |
| }
 | |
| 
 | |
| func serveMetrics(address string) {
 | |
| 	http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
 | |
| 		w.WriteHeader(http.StatusOK)
 | |
| 		w.Write([]byte("OK"))
 | |
| 	})
 | |
| 
 | |
| 	http.Handle("/metrics", promhttp.Handler())
 | |
| 
 | |
| 	log.Fatal(http.ListenAndServe(address, nil))
 | |
| }
 |