Skip to content

Commit 40f6229

Browse files
committed
feat(annotations): support multiple annotation prefixes
1 parent 49f7900 commit 40f6229

37 files changed

Lines changed: 833 additions & 66 deletions

controller/execute.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"net/http"
2323
"os"
2424
"os/signal"
25+
"slices"
26+
"strings"
2527
"syscall"
2628
"time"
2729

@@ -63,9 +65,9 @@ func execute(ctx context.Context) {
6365
}
6466

6567
// Set annotation prefix (required since init() was removed)
66-
annotations.SetAnnotationPrefix(cfg.AnnotationPrefix)
67-
if cfg.AnnotationPrefix != annotations.DefaultAnnotationPrefix {
68-
log.Infof("Using custom annotation prefix: %s", cfg.AnnotationPrefix)
68+
annotations.SetAnnotationPrefixes(cfg.AnnotationPrefixes...)
69+
if !slices.Equal(cfg.AnnotationPrefixes, []string{annotations.DefaultAnnotationPrefix, annotations.AlphaAnnotationPrefix}) {
70+
log.Infof("Using custom annotation prefixes: %s", strings.Join(cfg.AnnotationPrefixes, ","))
6971
}
7072

7173
if err := configureLogger(cfg); err != nil {

docs/annotations/annotations.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ The following table documents which sources support which annotations:
2929
[^4]: For Gateway API sources, annotation placement differs by type. See [Gateway API Annotation Placement](#gateway-api-annotation-placement) for details.
3030
[^5]: The annotation must be on the listener's `VirtualService`.
3131

32+
Annotation prefixes can be configured with the `--annotation-prefix` flag, the default prefixes are `external-dns.kubernetes.io/` and `external-dns.alpha.kubernetes.io/` (for backward compatibility).
33+
34+
!!!note "Annotation prefix deprecation"
35+
The `external-dns.alpha.kubernetes.io/` prefix is deprecated and will eventually be removed. It is recommended to use the `external-dns.kubernetes.io/` prefix for all annotations.
36+
For example, `external-dns.alpha.kubernetes.io/hostname` should be updated to `external-dns.kubernetes.io/hostname`.
37+
3238
## external-dns.kubernetes.io/access
3339

3440
Specifies which set of node IP addresses to use for a `Service` of type `NodePort`.

docs/flags.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ tags:
2020
| `--skipper-routegroup-groupversion="zalando.org/v1"` | The resource version for skipper routegroup |
2121
| `--[no-]always-publish-not-ready-addresses` | Always publish also not ready addresses for headless services (optional) |
2222
| `--annotation-filter=""` | Filter resources queried for endpoints by annotation, using label selector semantics |
23-
| `--annotation-prefix="external-dns.kubernetes.io/"` | Annotation prefix for external-dns annotations (default: external-dns.kubernetes.io/) |
23+
| `--annotation-prefix=external-dns.kubernetes.io/...` | Annotation prefix for external-dns annotations (default: external-dns.kubernetes.io/, ); specify multiple times to support additional prefixes |
2424
| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) |
2525
| `--connector-source-server="localhost:8080"` | The server to connect for connector source, valid only when using connector source |
2626
| `--crd-source-apiversion="externaldns.k8s.io/v1alpha1"` | API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source |

internal/flags/binders.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func (b *KingpinBinder) Int64Var(name, help string, def int64, target *int64) {
7777
}
7878

7979
func (b *KingpinBinder) StringsVar(name, help string, def []string, target *[]string) {
80+
*target = nil
8081
if len(def) > 0 {
8182
b.App.Flag(name, help).Default(def...).StringsVar(target)
8283
return

pkg/apis/externaldns/types.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type Config struct {
5656
Sources []string
5757
Namespace string
5858
AnnotationFilter string
59-
AnnotationPrefix string
59+
AnnotationPrefixes []string
6060
LabelFilter string
6161
IngressClassNames []string
6262
FQDNTemplate []string
@@ -241,7 +241,7 @@ var defaultConfig = &Config{
241241
AkamaiServiceConsumerDomain: "",
242242
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
243243
AnnotationFilter: "",
244-
AnnotationPrefix: annotations.DefaultAnnotationPrefix,
244+
AnnotationPrefixes: []string{annotations.DefaultAnnotationPrefix, annotations.AlphaAnnotationPrefix},
245245
APIServerURL: "",
246246
AWSAPIRetries: 3,
247247
AWSAssumeRole: "",
@@ -468,8 +468,8 @@ var allowedSources = []string{
468468
// NewConfig returns new Config object
469469
func NewConfig() *Config {
470470
return &Config{
471-
AnnotationPrefix: annotations.DefaultAnnotationPrefix,
472-
AWSSDCreateTag: map[string]string{},
471+
AnnotationPrefixes: []string{annotations.DefaultAnnotationPrefix, annotations.AlphaAnnotationPrefix},
472+
AWSSDCreateTag: map[string]string{},
473473
}
474474
}
475475

@@ -540,7 +540,7 @@ func bindFlags(b flags.FlagBinder, cfg *Config) {
540540
// Flags related to processing source
541541
b.BoolVar("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)", false, &cfg.AlwaysPublishNotReadyAddresses)
542542
b.StringVar("annotation-filter", "Filter resources queried for endpoints by annotation, using label selector semantics", defaultConfig.AnnotationFilter, &cfg.AnnotationFilter)
543-
b.StringVar("annotation-prefix", "Annotation prefix for external-dns annotations (default: external-dns.kubernetes.io/)", defaultConfig.AnnotationPrefix, &cfg.AnnotationPrefix)
543+
b.StringsVar("annotation-prefix", "Annotation prefix for external-dns annotations (default: external-dns.kubernetes.io/, ); specify multiple times to support additional prefixes", defaultConfig.AnnotationPrefixes, &cfg.AnnotationPrefixes)
544544
b.EnumVar("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)", defaultConfig.Compatibility, &cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller")
545545
b.StringVar("connector-source-server", "The server to connect for connector source, valid only when using connector source", defaultConfig.ConnectorSourceServer, &cfg.ConnectorSourceServer)
546546
b.StringVar("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source", defaultConfig.CRDSourceAPIVersion, &cfg.CRDSourceAPIVersion)

pkg/apis/externaldns/types_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ var (
4444
SkipperRouteGroupVersion: "zalando.org/v1",
4545
Sources: []string{"service"},
4646
Namespace: "",
47-
AnnotationPrefix: "external-dns.kubernetes.io/",
47+
AnnotationPrefixes: []string{"external-dns.kubernetes.io/", "external-dns.alpha.kubernetes.io/"},
4848
FQDNTemplate: nil,
4949
Compatibility: "",
5050
Provider: ProviderGoogle,
@@ -150,7 +150,7 @@ var (
150150
SkipperRouteGroupVersion: "zalando.org/v2",
151151
Sources: []string{"service", "ingress", "connector"},
152152
Namespace: "namespace",
153-
AnnotationPrefix: "external-dns.kubernetes.io/",
153+
AnnotationPrefixes: []string{"external-dns.example.com/", "external-dns.alpha.example.com/"},
154154
IgnoreHostnameAnnotation: true,
155155
IgnoreNonHostNetworkPods: true,
156156
IgnoreIngressTLSSpec: true,
@@ -312,6 +312,8 @@ func TestParseFlags(t *testing.T) {
312312
"--server=http://127.0.0.1:8080",
313313
"--kubeconfig=/some/path",
314314
"--request-timeout=77s",
315+
"--annotation-prefix=external-dns.example.com/",
316+
"--annotation-prefix=external-dns.alpha.example.com/",
315317
"--gloo-namespace=gloo-not-system",
316318
"--gloo-namespace=gloo-second-system",
317319
"--skipper-routegroup-groupversion=zalando.org/v2",
@@ -445,6 +447,7 @@ func TestParseFlags(t *testing.T) {
445447
"EXTERNAL_DNS_SERVER": "http://127.0.0.1:8080",
446448
"EXTERNAL_DNS_KUBECONFIG": "/some/path",
447449
"EXTERNAL_DNS_REQUEST_TIMEOUT": "77s",
450+
"EXTERNAL_DNS_ANNOTATION_PREFIX": "external-dns.example.com/\nexternal-dns.alpha.example.com/",
448451
"EXTERNAL_DNS_CONTOUR_LOAD_BALANCER": "heptio-contour-other/contour-other",
449452
"EXTERNAL_DNS_GLOO_NAMESPACE": "gloo-not-system\ngloo-second-system",
450453
"EXTERNAL_DNS_SKIPPER_ROUTEGROUP_GROUPVERSION": "zalando.org/v2",

pkg/apis/externaldns/validation/validation.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,16 @@ func ValidateConfig(cfg *externaldns.Config) error {
5656
return errors.New("--annotation-filter does not specify a valid label selector")
5757
}
5858

59-
if cfg.AnnotationPrefix == "" {
59+
if len(cfg.AnnotationPrefixes) == 0 {
6060
return errors.New("--annotation-prefix cannot be empty")
6161
}
62-
if !strings.HasSuffix(cfg.AnnotationPrefix, "/") {
63-
return errors.New("--annotation-prefix must end with '/'")
62+
for _, prefix := range cfg.AnnotationPrefixes {
63+
if len(prefix) == 0 {
64+
return errors.New("--annotation-prefix cannot be empty")
65+
}
66+
if !strings.HasSuffix(prefix, "/") {
67+
return errors.New("--annotation-prefix must end with '/'")
68+
}
6469
}
6570

6671
if cfg.KubeAPIQPS <= 0 {

0 commit comments

Comments
 (0)