Skip to content

Commit

Permalink
provider generic annotations
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Jansen <[email protected]>
  • Loading branch information
farodin91 committed Oct 11, 2023
1 parent 0725104 commit b076420
Show file tree
Hide file tree
Showing 39 changed files with 462 additions and 128 deletions.
8 changes: 8 additions & 0 deletions internal/testutils/mock_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package testutils

import (
"context"
"sigs.k8s.io/external-dns/pkg/apis"
"time"

"github.com/stretchr/testify/mock"
Expand Down Expand Up @@ -58,3 +59,10 @@ func (m *MockSource) AddEventHandler(ctx context.Context, handler func()) {
}
}()
}

func (b *MockSource) SetProviderSpecificConfig(_ apis.ProviderSpecificConfig) {
}

func (b *MockSource) GetProviderSpecificAnnotations(_ map[string]string) (endpoint.ProviderSpecific, string) {
return nil, ""
}
134 changes: 72 additions & 62 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,77 @@ func main() {
}
}

p, err := createProvider(cfg, err, domainFilter, zoneIDFilter, zoneTypeFilter, zoneTagFilter, awsSession, zoneNameFilter, ctx, endpointsSource)

if cfg.WebhookServer {
webhook.StartHTTPApi(p, nil, cfg.WebhookProviderReadTimeout, cfg.WebhookProviderWriteTimeout, "127.0.0.1:8888")
os.Exit(0)
}
ps, err := p.GetProviderSpecific(ctx)
if err != nil {
log.Fatal(err)
}
endpointsSource.SetProviderSpecificConfig(ps)

var r registry.Registry
switch cfg.Registry {
case "dynamodb":
config := awsSDK.NewConfig()
if cfg.AWSDynamoDBRegion != "" {
config = config.WithRegion(cfg.AWSDynamoDBRegion)
}
r, err = registry.NewDynamoDBRegistry(p, cfg.TXTOwnerID, dynamodb.New(awsSession, config), cfg.AWSDynamoDBTable, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, []byte(cfg.TXTEncryptAESKey), cfg.TXTCacheInterval)
case "noop":
r, err = registry.NewNoopRegistry(p)
case "txt":
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, cfg.TXTEncryptEnabled, []byte(cfg.TXTEncryptAESKey))
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,
ExcludeRecordTypes: cfg.ExcludeDNSRecordTypes,
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 createProvider(cfg *externaldns.Config, err error, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zoneTypeFilter provider.ZoneTypeFilter, zoneTagFilter provider.ZoneTagFilter, awsSession *session.Session, zoneNameFilter endpoint.DomainFilter, ctx context.Context, endpointsSource source.Source) (provider.Provider, error) {
var p provider.Provider
switch cfg.Provider {
case "akamai":
Expand Down Expand Up @@ -411,68 +482,7 @@ func main() {
if err != nil {
log.Fatal(err)
}

if cfg.WebhookServer {
webhook.StartHTTPApi(p, nil, cfg.WebhookProviderReadTimeout, cfg.WebhookProviderWriteTimeout, "127.0.0.1:8888")
os.Exit(0)
}

var r registry.Registry
switch cfg.Registry {
case "dynamodb":
config := awsSDK.NewConfig()
if cfg.AWSDynamoDBRegion != "" {
config = config.WithRegion(cfg.AWSDynamoDBRegion)
}
r, err = registry.NewDynamoDBRegistry(p, cfg.TXTOwnerID, dynamodb.New(awsSession, config), cfg.AWSDynamoDBTable, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, []byte(cfg.TXTEncryptAESKey), cfg.TXTCacheInterval)
case "noop":
r, err = registry.NewNoopRegistry(p)
case "txt":
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval, cfg.TXTWildcardReplacement, cfg.ManagedDNSRecordTypes, cfg.ExcludeDNSRecordTypes, cfg.TXTEncryptEnabled, []byte(cfg.TXTEncryptAESKey))
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,
ExcludeRecordTypes: cfg.ExcludeDNSRecordTypes,
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)
return p, err
}

func handleSigterm(cancel func()) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package apis

type ProviderSpecificConfig struct {
Translation map[string]string `json:"translation"`
PrefixTranslation map[string]string `json:"prefixTranslation"`
}
9 changes: 9 additions & 0 deletions provider/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package aws
import (
"context"
"fmt"
"sigs.k8s.io/external-dns/pkg/apis"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -278,6 +279,14 @@ func NewAWSProvider(awsConfig AWSConfig, client Route53API) (*AWSProvider, error
return provider, nil
}

func (p *AWSProvider) GetProviderSpecific(_ context.Context) (apis.ProviderSpecificConfig, error) {
return apis.ProviderSpecificConfig{
PrefixTranslation: map[string]string{
"external-dns.alpha.kubernetes.io/aws-": "aws/",
},
}, nil
}

// Zones returns the list of hosted zones.
func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53.HostedZone, error) {
if p.zonesCache.zones != nil && time.Since(p.zonesCache.age) < p.zonesCache.duration {
Expand Down
22 changes: 16 additions & 6 deletions provider/cloudflare/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"
"os"
"sigs.k8s.io/external-dns/pkg/apis"
"strconv"
"strings"

Expand All @@ -29,7 +30,6 @@ import (
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
"sigs.k8s.io/external-dns/source"
)

const (
Expand All @@ -41,6 +41,8 @@ const (
cloudFlareUpdate = "UPDATE"
// defaultCloudFlareRecordTTL 1 = automatic
defaultCloudFlareRecordTTL = 1
// The annotation used for determining if traffic will go through Cloudflare
CloudflareProxiedKey = "external-dns.alpha.kubernetes.io/cloudflare-proxied"
)

// We have to use pointers to bools now, as the upstream cloudflare-go library requires them
Expand Down Expand Up @@ -161,7 +163,7 @@ func getCreateDNSRecordParam(cfc cloudFlareChange) cloudflare.CreateDNSRecordPar
}

// NewCloudFlareProvider initializes a new CloudFlare DNS based Provider.
func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, proxiedByDefault bool, dryRun bool, dnsRecordsPerPage int) (*CloudFlareProvider, error) {
func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, proxiedByDefault bool, dryRun bool, dnsRecordsPerPage int) (provider.Provider, error) {
// initialize via chosen auth method and returns new API object
var (
config *cloudflare.API
Expand Down Expand Up @@ -195,6 +197,14 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov
return provider, nil
}

func (p *CloudFlareProvider) GetProviderSpecific(_ context.Context) (apis.ProviderSpecificConfig, error) {
return apis.ProviderSpecificConfig{
Translation: map[string]string{
CloudflareProxiedKey: CloudflareProxiedKey,
},
}, nil
}

// Zones returns the list of hosted zones.
func (p *CloudFlareProvider) Zones(ctx context.Context) ([]cloudflare.Zone, error) {
result := []cloudflare.Zone{}
Expand Down Expand Up @@ -375,7 +385,7 @@ func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]
if proxied {
e.RecordTTL = 0
}
e.SetProviderSpecificProperty(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
e.SetProviderSpecificProperty(CloudflareProxiedKey, strconv.FormatBool(proxied))

adjustedEndpoints = append(adjustedEndpoints, e)
}
Expand Down Expand Up @@ -457,10 +467,10 @@ func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
proxied := proxiedByDefault

for _, v := range endpoint.ProviderSpecific {
if v.Name == source.CloudflareProxiedKey {
if v.Name == CloudflareProxiedKey {
b, err := strconv.ParseBool(v.Value)
if err != nil {
log.Errorf("Failed to parse annotation [%s]: %v", source.CloudflareProxiedKey, err)
log.Errorf("Failed to parse annotation [%s]: %v", CloudflareProxiedKey, err)
} else {
proxied = b
}
Expand Down Expand Up @@ -505,7 +515,7 @@ func groupByNameAndType(records []cloudflare.DNSRecord) []*endpoint.Endpoint {
records[0].Type,
endpoint.TTL(records[0].TTL),
targets...).
WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(*records[0].Proxied)),
WithProviderSpecific(CloudflareProxiedKey, strconv.FormatBool(*records[0].Proxied)),
)
}

Expand Down
11 changes: 10 additions & 1 deletion provider/ibmcloud/ibmcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"os"
"reflect"
"sigs.k8s.io/external-dns/pkg/apis"
"strconv"
"strings"

Expand Down Expand Up @@ -301,7 +302,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter
// NewIBMCloudProvider creates a new IBMCloud provider.
//
// Returns the provider or an error if a provider could not be created.
func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, source source.Source, proxiedByDefault bool, dryRun bool) (*IBMCloudProvider, error) {
func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, source source.Source, proxiedByDefault bool, dryRun bool) (provider.Provider, error) {
cfg, err := getConfig(configFile)
if err != nil {
return nil, err
Expand Down Expand Up @@ -335,6 +336,14 @@ func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter,
return provider, nil
}

func (p *IBMCloudProvider) GetProviderSpecific(_ context.Context) (apis.ProviderSpecificConfig, error) {
return apis.ProviderSpecificConfig{
PrefixTranslation: map[string]string{
"external-dns.alpha.kubernetes.io/aws-": "aws/",
},
}, nil
}

// Records gets the current records.
//
// Returns the current records or an error if the operation failed.
Expand Down
7 changes: 7 additions & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package provider
import (
"context"
"net"
"sigs.k8s.io/external-dns/pkg/apis"
"strings"

"sigs.k8s.io/external-dns/endpoint"
Expand All @@ -36,8 +37,10 @@ type Provider interface {
// the endpoints that the provider returns in `Records` so that the change plan will not have
// unnecessary (potentially failing) changes. It may also modify other fields, add, or remove
// Endpoints. It is permitted to modify the supplied endpoints.
// BaseProvider will remove all generic ProviderSpecific from all endpoints.
AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoint.Endpoint, error)
GetDomainFilter() endpoint.DomainFilter
GetProviderSpecific(ctx context.Context) (apis.ProviderSpecificConfig, error)
}

type BaseProvider struct{}
Expand All @@ -50,6 +53,10 @@ func (b BaseProvider) GetDomainFilter() endpoint.DomainFilter {
return endpoint.DomainFilter{}
}

func (b BaseProvider) GetProviderSpecific(_ context.Context) (apis.ProviderSpecificConfig, error) {
return apis.ProviderSpecificConfig{}, nil
}

type contextKey struct {
name string
}
Expand Down
Loading

0 comments on commit b076420

Please sign in to comment.