mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
Merge a19a8e6a8a
into fe7940ce0a
This commit is contained in:
commit
59fe3da341
@ -229,6 +229,7 @@ func buildProvider(
|
||||
cloudflare.DNSRecordsConfig{
|
||||
PerPage: cfg.CloudflareDNSRecordsPerPage,
|
||||
Comment: cfg.CloudflareDNSRecordsComment,
|
||||
Tags: cfg.CloudflareDNSRecordsTags,
|
||||
})
|
||||
case "google":
|
||||
p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.GoogleZoneVisibility, cfg.DryRun)
|
||||
|
@ -96,6 +96,7 @@
|
||||
| `--[no-]cloudflare-regional-services` | When using the Cloudflare provider, specify if Regional Services feature will be used (default: disabled) |
|
||||
| `--cloudflare-region-key=CLOUDFLARE-REGION-KEY` | When using the Cloudflare provider, specify the default region for Regional Services. Any value other than an empty string will enable the Regional Services feature (optional) |
|
||||
| `--cloudflare-record-comment=""` | When using the Cloudflare provider, specify the comment for the DNS records (default: '') |
|
||||
| `--cloudflare-record-tags=""` | When using the Cloudflare provider for a paid zone, specify the tags for the DNS records as a comma-separated string (default: '') |
|
||||
| `--coredns-prefix="/skydns/"` | When using the CoreDNS provider, specify the prefix name |
|
||||
| `--akamai-serviceconsumerdomain=""` | When using the Akamai provider, specify the base URL (required when --provider=akamai and edgerc-path not specified) |
|
||||
| `--akamai-client-token=""` | When using the Akamai provider, specify the client token (required when --provider=akamai and edgerc-path not specified) |
|
||||
|
@ -111,6 +111,7 @@ type Config struct {
|
||||
CloudflareCustomHostnames bool
|
||||
CloudflareDNSRecordsPerPage int
|
||||
CloudflareDNSRecordsComment string
|
||||
CloudflareDNSRecordsTags string
|
||||
CloudflareCustomHostnamesMinTLSVersion string
|
||||
CloudflareCustomHostnamesCertificateAuthority string
|
||||
CloudflareRegionalServices bool
|
||||
@ -535,6 +536,7 @@ func App(cfg *Config) *kingpin.Application {
|
||||
app.Flag("cloudflare-regional-services", "When using the Cloudflare provider, specify if Regional Services feature will be used (default: disabled)").Default(strconv.FormatBool(defaultConfig.CloudflareRegionalServices)).BoolVar(&cfg.CloudflareRegionalServices)
|
||||
app.Flag("cloudflare-region-key", "When using the Cloudflare provider, specify the default region for Regional Services. Any value other than an empty string will enable the Regional Services feature (optional)").StringVar(&cfg.CloudflareRegionKey)
|
||||
app.Flag("cloudflare-record-comment", "When using the Cloudflare provider, specify the comment for the DNS records (default: '')").Default("").StringVar(&cfg.CloudflareDNSRecordsComment)
|
||||
app.Flag("cloudflare-record-tags", "When using the Cloudflare provider for a paid zone, specify the tags for the DNS records as a comma-separated string (default: '')").Default("").StringVar(&cfg.CloudflareDNSRecordsTags)
|
||||
|
||||
app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix)
|
||||
app.Flag("akamai-serviceconsumerdomain", "When using the Akamai provider, specify the base URL (required when --provider=akamai and edgerc-path not specified)").Default(defaultConfig.AkamaiServiceConsumerDomain).StringVar(&cfg.AkamaiServiceConsumerDomain)
|
||||
|
@ -170,6 +170,7 @@ func (z zoneService) CreateCustomHostname(ctx context.Context, zoneID string, ch
|
||||
type DNSRecordsConfig struct {
|
||||
PerPage int
|
||||
Comment string
|
||||
Tags string
|
||||
}
|
||||
|
||||
func (c *DNSRecordsConfig) trimAndValidateComment(dnsName, comment string, paidZone func(string) bool) string {
|
||||
@ -190,12 +191,41 @@ func (c *DNSRecordsConfig) trimAndValidateComment(dnsName, comment string, paidZ
|
||||
return comment
|
||||
}
|
||||
|
||||
func (c *DNSRecordsConfig) validTags(dnsName string, paidZone func(string) bool, tagsFromAnnotation []string) []string {
|
||||
if len(tagsFromAnnotation) > 0 || c.Tags != "" {
|
||||
paidZone := paidZone(dnsName)
|
||||
if !paidZone {
|
||||
log.Warnf("DNS record tags are not supported for free zones. Skipping for %s", dnsName)
|
||||
c.Tags = ""
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(tagsFromAnnotation) > 0 {
|
||||
sort.Strings(tagsFromAnnotation)
|
||||
return tagsFromAnnotation
|
||||
}
|
||||
|
||||
if c.Tags != "" {
|
||||
tags := strings.Split(c.Tags, ",")
|
||||
sort.Strings(tags)
|
||||
return tags
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CloudFlareProvider) ZoneHasPaidPlan(hostname string) bool {
|
||||
zone, err := publicsuffix.EffectiveTLDPlusOne(hostname)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get effective TLD+1 for hostname %s %v", hostname, err)
|
||||
return false
|
||||
}
|
||||
|
||||
if paidZone, ok := p.PaidZones[zone]; ok {
|
||||
return paidZone
|
||||
}
|
||||
|
||||
zoneID, err := p.Client.ZoneIDByName(zone)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get zone %s by name %v", zone, err)
|
||||
@ -208,7 +238,8 @@ func (p *CloudFlareProvider) ZoneHasPaidPlan(hostname string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
return zoneDetails.Plan.IsSubscribed
|
||||
p.PaidZones[zone] = zoneDetails.Plan.IsSubscribed
|
||||
return p.PaidZones[zone]
|
||||
}
|
||||
|
||||
// CloudFlareProvider is an implementation of Provider for CloudFlare DNS.
|
||||
@ -223,6 +254,7 @@ type CloudFlareProvider struct {
|
||||
CustomHostnamesConfig CustomHostnamesConfig
|
||||
DNSRecordsConfig DNSRecordsConfig
|
||||
RegionalServicesConfig RegionalServicesConfig
|
||||
PaidZones map[string]bool
|
||||
}
|
||||
|
||||
// cloudFlareChange differentiates between ChangeActions
|
||||
@ -248,7 +280,8 @@ func updateDNSRecordParam(cfc cloudFlareChange) cloudflare.UpdateDNSRecordParams
|
||||
Type: cfc.ResourceRecord.Type,
|
||||
Content: cfc.ResourceRecord.Content,
|
||||
Priority: cfc.ResourceRecord.Priority,
|
||||
Comment: cloudflare.StringPtr(cfc.ResourceRecord.Comment),
|
||||
Comment: &cfc.ResourceRecord.Comment,
|
||||
Tags: cfc.ResourceRecord.Tags,
|
||||
}
|
||||
|
||||
return params
|
||||
@ -264,6 +297,7 @@ func getCreateDNSRecordParam(cfc cloudFlareChange) cloudflare.CreateDNSRecordPar
|
||||
Content: cfc.ResourceRecord.Content,
|
||||
Priority: cfc.ResourceRecord.Priority,
|
||||
Comment: cfc.ResourceRecord.Comment,
|
||||
Tags: cfc.ResourceRecord.Tags,
|
||||
}
|
||||
|
||||
return params
|
||||
@ -339,6 +373,7 @@ func NewCloudFlareProvider(
|
||||
DryRun: dryRun,
|
||||
RegionalServicesConfig: regionalServicesConfig,
|
||||
DNSRecordsConfig: dnsRecordsConfig,
|
||||
PaidZones: make(map[string]bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -595,11 +630,13 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
|
||||
|
||||
for _, change := range zoneChanges {
|
||||
logFields := log.Fields{
|
||||
"record": change.ResourceRecord.Name,
|
||||
"type": change.ResourceRecord.Type,
|
||||
"ttl": change.ResourceRecord.TTL,
|
||||
"action": change.Action.String(),
|
||||
"zone": zoneID,
|
||||
"record": change.ResourceRecord.Name,
|
||||
"type": change.ResourceRecord.Type,
|
||||
"ttl": change.ResourceRecord.TTL,
|
||||
"action": change.Action,
|
||||
"zone": zoneID,
|
||||
"comment": change.ResourceRecord.Comment,
|
||||
"tags": change.ResourceRecord.Tags,
|
||||
}
|
||||
|
||||
log.WithFields(logFields).Info("Changing record.")
|
||||
@ -716,6 +753,14 @@ func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]
|
||||
}
|
||||
}
|
||||
|
||||
// if _, ok := e.GetProviderSpecificProperty(annotations.CloudflareRecordCommentKey); !ok {
|
||||
// e.SetProviderSpecificProperty(annotations.CloudflareRecordCommentKey, p.DNSRecordsConfig.Comment)
|
||||
// }
|
||||
|
||||
// if _, ok := e.GetProviderSpecificProperty(annotations.CloudflareRecordTagsKey); !ok {
|
||||
// e.SetProviderSpecificProperty(annotations.CloudflareRecordTagsKey, p.DNSRecordsConfig.Tags)
|
||||
// }
|
||||
|
||||
adjustedEndpoints = append(adjustedEndpoints, e)
|
||||
}
|
||||
return adjustedEndpoints, nil
|
||||
@ -809,6 +854,13 @@ func (p *CloudFlareProvider) newCloudFlareChange(action changeAction, ep *endpoi
|
||||
}
|
||||
}
|
||||
|
||||
var tagsFromAnnotation []string
|
||||
// Load tags from program flag
|
||||
if val, ok := ep.GetProviderSpecificProperty(annotations.CloudflareRecordTagsKey); ok {
|
||||
// Replace comment with Ingress annotation
|
||||
tagsFromAnnotation = strings.Split(val, ",")
|
||||
}
|
||||
|
||||
return &cloudFlareChange{
|
||||
Action: action,
|
||||
ResourceRecord: cloudflare.DNSRecord{
|
||||
@ -821,6 +873,7 @@ func (p *CloudFlareProvider) newCloudFlareChange(action changeAction, ep *endpoi
|
||||
Content: target,
|
||||
Comment: comment,
|
||||
Priority: priority,
|
||||
Tags: p.DNSRecordsConfig.validTags(ep.DNSName, p.ZoneHasPaidPlan, tagsFromAnnotation),
|
||||
},
|
||||
RegionalHostname: p.regionalHostname(ep),
|
||||
CustomHostnamesPrev: prevCustomHostnames,
|
||||
@ -996,6 +1049,10 @@ func (p *CloudFlareProvider) groupByNameAndTypeWithCustomHostnames(records DNSRe
|
||||
e = e.WithProviderSpecific(annotations.CloudflareRecordCommentKey, records[0].Comment)
|
||||
}
|
||||
|
||||
if len(records[0].Tags) > 0 {
|
||||
e = e.WithProviderSpecific(annotations.CloudflareRecordTagsKey, strings.Join(records[0].Tags, ","))
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
return endpoints
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -1913,6 +1914,73 @@ func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
tagsTestCases := []struct {
|
||||
name string
|
||||
provider *CloudFlareProvider
|
||||
endpoint *endpoint.Endpoint
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "For free Zones setting Tags, expect them to be ignored",
|
||||
provider: p,
|
||||
endpoint: &endpoint.Endpoint{
|
||||
DNSName: "example.com",
|
||||
RecordType: "A",
|
||||
Targets: []string{"192.0.2.1"},
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: annotations.CloudflareRecordTagsKey,
|
||||
Value: "tag1,tag2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "For paid Zones setting tags, expect them to be set",
|
||||
provider: paidProvider,
|
||||
endpoint: &endpoint.Endpoint{
|
||||
DNSName: "bar.com",
|
||||
RecordType: "A",
|
||||
Targets: []string{"192.0.2.1"},
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: annotations.CloudflareRecordTagsKey,
|
||||
Value: "tag1,tag2",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"tag1", "tag2"},
|
||||
},
|
||||
{
|
||||
name: "For paid Zones settings tags not alphabetically sorted, expect them to be sorted",
|
||||
provider: paidProvider,
|
||||
endpoint: &endpoint.Endpoint{
|
||||
DNSName: "bar.com",
|
||||
RecordType: "A",
|
||||
Targets: []string{"192.0.2.1"},
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: annotations.CloudflareRecordTagsKey,
|
||||
Value: "tag2,tag1",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"tag1", "tag2"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tagsTestCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
change, _ := test.provider.newCloudFlareChange(cloudFlareCreate, test.endpoint, test.endpoint.Targets[0], nil)
|
||||
if test.expected == nil && len(change.ResourceRecord.Tags) != 0 {
|
||||
t.Errorf("expected tags to be %v, but got %v", test.expected, change.ResourceRecord.Tags)
|
||||
} else if !reflect.DeepEqual(change.ResourceRecord.Tags, test.expected) {
|
||||
t.Errorf("expected tags to be %v, but got %v", test.expected, change.ResourceRecord.Tags)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFlareProvider_submitChangesCNAME(t *testing.T) {
|
||||
@ -2578,6 +2646,7 @@ func TestZoneHasPaidPlan(t *testing.T) {
|
||||
Client: client,
|
||||
domainFilter: endpoint.NewDomainFilter([]string{"foo.com", "bar.com"}),
|
||||
zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
||||
PaidZones: make(map[string]bool),
|
||||
}
|
||||
|
||||
assert.False(t, cfprovider.ZoneHasPaidPlan("subdomain.foo.com"))
|
||||
@ -2589,6 +2658,7 @@ func TestZoneHasPaidPlan(t *testing.T) {
|
||||
Client: client,
|
||||
domainFilter: endpoint.NewDomainFilter([]string{"foo.com", "bar.com"}),
|
||||
zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
||||
PaidZones: make(map[string]bool),
|
||||
}
|
||||
assert.False(t, cfproviderWithZoneError.ZoneHasPaidPlan("subdomain.foo.com"))
|
||||
}
|
||||
|
@ -23,10 +23,11 @@ const (
|
||||
AnnotationKeyPrefix = "external-dns.alpha.kubernetes.io/"
|
||||
|
||||
// CloudflareProxiedKey The annotation used for determining if traffic will go through Cloudflare
|
||||
CloudflareProxiedKey = AnnotationKeyPrefix + "cloudflare-proxied"
|
||||
CloudflareCustomHostnameKey = AnnotationKeyPrefix + "cloudflare-custom-hostname"
|
||||
CloudflareRegionKey = AnnotationKeyPrefix + "cloudflare-region-key"
|
||||
CloudflareRecordCommentKey = AnnotationKeyPrefix + "cloudflare-record-comment"
|
||||
CloudflareProxiedKey = "external-dns.alpha.kubernetes.io/cloudflare-proxied"
|
||||
CloudflareCustomHostnameKey = "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname"
|
||||
CloudflareRegionKey = "external-dns.alpha.kubernetes.io/cloudflare-region-key"
|
||||
CloudflareRecordCommentKey = "external-dns.alpha.kubernetes.io/cloudflare-record-comment"
|
||||
CloudflareRecordTagsKey = "external-dns.alpha.kubernetes.io/cloudflare-record-tags"
|
||||
|
||||
AWSPrefix = AnnotationKeyPrefix + "aws-"
|
||||
SCWPrefix = AnnotationKeyPrefix + "scw-"
|
||||
|
@ -73,6 +73,11 @@ func ProviderSpecificAnnotations(annotations map[string]string) (endpoint.Provid
|
||||
Name: CloudflareRecordCommentKey,
|
||||
Value: v,
|
||||
})
|
||||
} else if strings.Contains(k, CloudflareRecordTagsKey) {
|
||||
providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{
|
||||
Name: CloudflareRecordTagsKey,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user