Skip to content

Commit

Permalink
Treat any annotations with a recognised prefix, but that are not othe…
Browse files Browse the repository at this point in the history
…rwise recognised, as provider properties.

Replace '/' characters in provider property names with '-'.
Add annotation support to the `DNSEndpoint` custom resource source.
  • Loading branch information
Dadeos-Menlo committed Feb 28, 2025
1 parent 1f04079 commit 15f7b9e
Show file tree
Hide file tree
Showing 18 changed files with 238 additions and 435 deletions.
10 changes: 8 additions & 2 deletions docs/annotations/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The following table documents which sources support which annotations:
| Connector | | | | | | |
| Contour | Yes | Yes[^1] | | Yes | Yes | Yes |
| CloudFoundry | | | | | | |
| CRD | | | | | | |
| CRD | | Yes | | Yes | Yes | Yes |
| F5 | | | | Yes | Yes | |
| Gateway | Yes | Yes[^1] | | Yes[^4] | Yes | Yes |
| Gloo | | | | Yes | Yes[^5] | Yes[^5] |
Expand Down Expand Up @@ -101,7 +101,13 @@ It must be between 1 and 2,147,483,647 seconds.

## Provider-specific annotations

Some providers define their own annotations. Cloud-specific annotations have keys prefixed as follows:
Provider-specific annotations are prefixed by `external-dns.alpha.kubernetes.io/`
and the provider's name, for example `external-dns.alpha.kubernetes.io/aws-`.

Individual provider implementations should be examined to identify the additional
configuration offered via supported annotations.

Currently, supported Cloud-specific annotations include the following prefixes:

| Cloud | Annotation prefix |
|------------|------------------------------------------------|
Expand Down
21 changes: 7 additions & 14 deletions docs/sources/crd/dnsendpoint-aws-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,10 @@ apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: examplednsrecord
spec:
endpoints:
- dnsName: subdomain.foo.bar.com
providerSpecific:
- name: "aws/failover"
value: "PRIMARY"
- name: "aws/health-check-id"
value: "asdf1234-as12-as12-as12-asdf12345678"
- name: "aws/evaluate-target-health"
value: "true"
recordType: CNAME
setIdentifier: some-unique-id
targets:
- other-subdomain.foo.bar.com
annotations:
external-dns.alpha.kubernetes.io/hostname: "subdomain.foo.bar.com"
external-dns.alpha.kubernetes.io/target: "other-subdomain.foo.bar.com"
external-dns.alpha.kubernetes.io/set-identifier: "some-unique-id"
external-dns.alpha.kubernetes.io/aws-failover: "PRIMARY"
external-dns.alpha.kubernetes.io/aws-health-check-id: "asdf1234-as12-as12-as12-asdf12345678"
external-dns.alpha.kubernetes.io/aws-evaluate-target-health: "true"
16 changes: 5 additions & 11 deletions docs/sources/crd/dnsendpoint-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@ apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: examplednsrecord
spec:
endpoints:
- dnsName: foo.bar.com
recordTTL: 180
recordType: A
targets:
- 192.168.99.216
# Provider specific configurations are set like an annotation would on other sources
providerSpecific:
- name: external-dns.alpha.kubernetes.io/cloudflare-proxied
value: "true"
annotations:
external-dns.alpha.kubernetes.io/hostname: foo.bar.com
external-dns.alpha.kubernetes.io/target: 192.168.99.216
external-dns.alpha.kubernetes.io/ttl: "180"
external-dns.alpha.kubernetes.io/cloudflare-proxied: "true"
6 changes: 0 additions & 6 deletions docs/tutorials/webhook-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ The default recommended port for the provider endpoints is `8888`, and should li

The default recommended port for the exposed endpoints is `8080`, and it should be bound to all interfaces (`0.0.0.0`)

## Custom Annotations

The Webhook provider supports custom annotations for DNS records. This feature allows users to define additional configuration options for DNS records managed by the Webhook provider. Custom annotations are defined using the annotation format `external-dns.alpha.kubernetes.io/webhook-<custom-annotation>`.

Custom annotations can be used to influence DNS record creation and updates. Providers implementing the Webhook API should document the custom annotations they support and how they affect DNS record management.

## Provider registry

To simplify the discovery of providers, we will accept pull requests that will add links to providers in this documentation.
Expand Down
20 changes: 10 additions & 10 deletions provider/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,19 @@ const (
route53PageSize int32 = 300
// providerSpecificAlias specifies whether a CNAME endpoint maps to an AWS ALIAS record.
providerSpecificAlias = "alias"
providerSpecificTargetHostedZone = "aws/target-hosted-zone"
providerSpecificTargetHostedZone = "aws-target-hosted-zone"
// providerSpecificEvaluateTargetHealth specifies whether an AWS ALIAS record
// has the EvaluateTargetHealth field set to true. Present iff the endpoint
// has a `providerSpecificAlias` value of `true`.
providerSpecificEvaluateTargetHealth = "aws/evaluate-target-health"
providerSpecificWeight = "aws/weight"
providerSpecificRegion = "aws/region"
providerSpecificFailover = "aws/failover"
providerSpecificGeolocationContinentCode = "aws/geolocation-continent-code"
providerSpecificGeolocationCountryCode = "aws/geolocation-country-code"
providerSpecificGeolocationSubdivisionCode = "aws/geolocation-subdivision-code"
providerSpecificMultiValueAnswer = "aws/multi-value-answer"
providerSpecificHealthCheckID = "aws/health-check-id"
providerSpecificEvaluateTargetHealth = "aws-evaluate-target-health"
providerSpecificWeight = "aws-weight"
providerSpecificRegion = "aws-region"
providerSpecificFailover = "aws-failover"
providerSpecificGeolocationContinentCode = "aws-geolocation-continent-code"
providerSpecificGeolocationCountryCode = "aws-geolocation-country-code"
providerSpecificGeolocationSubdivisionCode = "aws-geolocation-subdivision-code"
providerSpecificMultiValueAnswer = "aws-multi-value-answer"
providerSpecificHealthCheckID = "aws-health-check-id"
sameZoneAlias = "same-zone"
)

Expand Down
17 changes: 10 additions & 7 deletions provider/cloudflare/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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 @@ -44,6 +43,10 @@ const (
cloudFlareUpdate = "UPDATE"
// defaultCloudFlareRecordTTL 1 = automatic
defaultCloudFlareRecordTTL = 1

providerSpecificCustomHostnameKey = "cloudflare-custom-hostname"
// providerSpecificProxied specifies whether traffic will go through Cloudflare
providerSpecificProxied = "cloudflare-proxied"
)

// We have to use pointers to bools now, as the upstream cloudflare-go library requires them
Expand Down Expand Up @@ -499,7 +502,7 @@ func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]
if proxied {
e.RecordTTL = 0
}
e.SetProviderSpecificProperty(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
e.SetProviderSpecificProperty(providerSpecificProxied, strconv.FormatBool(proxied))

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

for _, v := range endpoint.ProviderSpecific {
if v.Name == source.CloudflareProxiedKey {
if v.Name == providerSpecificProxied {
b, err := strconv.ParseBool(v.Value)
if err != nil {
log.Errorf("Failed to parse annotation [%s]: %v", source.CloudflareProxiedKey, err)
log.Errorf("Failed parsing value of %s: %v", providerSpecificProxied, err)
} else {
proxied = b
}
Expand All @@ -666,7 +669,7 @@ func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {

func getEndpointCustomHostname(endpoint *endpoint.Endpoint) string {
for _, v := range endpoint.ProviderSpecific {
if v.Name == source.CloudflareCustomHostnameKey {
if v.Name == providerSpecificCustomHostnameKey {
return v.Value
}
}
Expand Down Expand Up @@ -721,9 +724,9 @@ func groupByNameAndTypeWithCustomHostnames(records []cloudflare.DNSRecord, chs [
if ep == nil {
continue
}
ep.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
ep.WithProviderSpecific(providerSpecificProxied, strconv.FormatBool(proxied))
if customHostname, ok := customOriginServers[records[0].Name]; ok {
ep.WithProviderSpecific(source.CloudflareCustomHostnameKey, customHostname)
ep.WithProviderSpecific(providerSpecificCustomHostnameKey, customHostname)
}

endpoints = append(endpoints, ep)
Expand Down
32 changes: 16 additions & 16 deletions provider/cloudflare/cloudflare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ func TestCloudflareProxiedOverrideTrue(t *testing.T) {
Targets: endpoint.Targets{"127.0.0.1"},
ProviderSpecific: endpoint.ProviderSpecific{
endpoint.ProviderSpecificProperty{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "true",
},
},
Expand Down Expand Up @@ -555,7 +555,7 @@ func TestCloudflareProxiedOverrideFalse(t *testing.T) {
Targets: endpoint.Targets{"127.0.0.1"},
ProviderSpecific: endpoint.ProviderSpecific{
endpoint.ProviderSpecificProperty{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -587,7 +587,7 @@ func TestCloudflareProxiedOverrideIllegal(t *testing.T) {
Targets: endpoint.Targets{"127.0.0.1"},
ProviderSpecific: endpoint.ProviderSpecific{
endpoint.ProviderSpecificProperty{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "asfasdfa",
},
},
Expand Down Expand Up @@ -638,7 +638,7 @@ func TestCloudflareSetProxied(t *testing.T) {
Targets: endpoint.Targets{"127.0.0.1"},
ProviderSpecific: endpoint.ProviderSpecific{
endpoint.ProviderSpecificProperty{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "true",
},
},
Expand Down Expand Up @@ -1008,7 +1008,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -1042,7 +1042,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -1090,7 +1090,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand All @@ -1103,7 +1103,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -1144,7 +1144,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand All @@ -1157,7 +1157,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -1198,7 +1198,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "false",
},
},
Expand Down Expand Up @@ -1338,7 +1338,7 @@ func TestCloudflareComplexUpdate(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "true",
},
},
Expand Down Expand Up @@ -1423,7 +1423,7 @@ func TestCustomTTLWithEnabledProxyNotChanged(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
Name: providerSpecificProxied,
Value: "true",
},
},
Expand Down Expand Up @@ -1653,7 +1653,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
Name: providerSpecificCustomHostnameKey,
Value: "a.foo.fancybar.com",
},
},
Expand All @@ -1666,7 +1666,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
Name: providerSpecificCustomHostnameKey,
Value: "txt.foo.fancybar.com",
},
},
Expand All @@ -1688,7 +1688,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
Name: providerSpecificCustomHostnameKey,
Value: "a2.foo.fancybar.com",
},
},
Expand Down
2 changes: 1 addition & 1 deletion provider/ibmcloud/ibmcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
if v.Name == proxyFilter {
b, err := strconv.ParseBool(v.Value)
if err != nil {
log.Errorf("Failed to parse annotation [%s]: %v", proxyFilter, err)
log.Errorf("Failed parsing value of %s: %v", proxyFilter, err)
} else {
proxied = b
}
Expand Down
14 changes: 7 additions & 7 deletions provider/ibmcloud/ibmcloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func newTestIBMCloudProvider(private bool) *IBMCloudProvider {
Targets: endpoint.Targets{"4.3.2.1"},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-vpc",
Name: vpcFilter,
Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
},
},
Expand Down Expand Up @@ -223,7 +223,7 @@ func TestPublic_ApplyChanges(t *testing.T) {
Targets: endpoint.NewTargets("4.3.2.1"),
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-proxied",
Name: proxyFilter,
Value: "false",
},
},
Expand All @@ -237,7 +237,7 @@ func TestPublic_ApplyChanges(t *testing.T) {
Targets: endpoint.NewTargets("1.2.3.4"),
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-proxied",
Name: proxyFilter,
Value: "false",
},
},
Expand All @@ -251,7 +251,7 @@ func TestPublic_ApplyChanges(t *testing.T) {
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-proxied",
Name: proxyFilter,
Value: "true",
},
},
Expand Down Expand Up @@ -284,7 +284,7 @@ func TestPrivate_ApplyChanges(t *testing.T) {
Targets: endpoint.NewTargets("4.3.2.1"),
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-vpc",
Name: vpcFilter,
Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
},
},
Expand Down Expand Up @@ -352,7 +352,7 @@ func TestAdjustEndpoints(t *testing.T) {
Labels: endpoint.Labels{},
ProviderSpecific: endpoint.ProviderSpecific{
{
Name: "ibmcloud-proxied",
Name: proxyFilter,
Value: "1",
},
},
Expand All @@ -364,7 +364,7 @@ func TestAdjustEndpoints(t *testing.T) {

assert.Equal(t, endpoint.TTL(0), ep[0].RecordTTL)
assert.Equal(t, "test.example.com", ep[0].DNSName)
proxied, _ := ep[0].GetProviderSpecificProperty("ibmcloud-proxied")
proxied, _ := ep[0].GetProviderSpecificProperty(proxyFilter)
assert.Equal(t, "true", proxied)
}

Expand Down
Loading

0 comments on commit 15f7b9e

Please sign in to comment.