From cd52a9c7ad286dd6472f2e622673953335694117 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 27 Feb 2026 12:08:47 +0000 Subject: [PATCH 01/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 52 +++++++++---------- internal/gen/docs/sources/main.go | 21 +++++--- internal/gen/docs/sources/main_test.go | 4 ++ .../gen/docs/sources/templates/sources.gotpl | 6 +-- source/ambassador_host.go | 1 + source/connector.go | 1 + source/contour_httpproxy.go | 1 + source/crd.go | 1 + source/empty.go | 1 + source/f5_transportserver.go | 1 + source/f5_virtualserver.go | 1 + source/fake.go | 1 + source/gateway.go | 5 ++ source/gloo_proxy.go | 1 + source/ingress.go | 1 + source/istio_gateway.go | 1 + source/istio_virtualservice.go | 1 + source/kong_tcpingress.go | 1 + source/node.go | 1 + source/openshift_route.go | 1 + source/pod.go | 1 + source/service.go | 1 + source/skipper_routegroup.go | 1 + source/traefik_proxy.go | 1 + 24 files changed, 70 insertions(+), 37 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 269edc9680..1e3d646133 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -22,32 +22,32 @@ Sources are responsible for: ## Available Sources -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Category | -|:----------------|:----------|:--------|:----------|:--------------|:---------|:---------| -| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | ingress controllers | -| **connector** | Remote TCP Server | | | false | false | special | -| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | false | externaldns | -| **empty** | None | | | false | false | testing | -| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **fake** | Fake Endpoints | | | true | true | testing | -| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | gateway api | -| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | false | kubernetes core | -| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | service mesh | -| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | service mesh | -| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | ingress controllers | -| **node** | Node | annotation,label | all | true | false | kubernetes core | -| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | openshift | -| **pod** | Pod | annotation,label | all,single | true | false | kubernetes core | -| **service** | Service | annotation,label | all,single | true | false | kubernetes core | -| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | ingress controllers | -| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | ingress controllers | +| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | +|:----------------|:----------|:--------|:----------|:--------------|:---------|:------------------|:---------| +| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | +| **connector** | Remote TCP Server | | | false | false | false | special | +| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | +| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | false | false | externaldns | +| **empty** | None | | | false | false | false | testing | +| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | +| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | +| **fake** | Fake Endpoints | | | true | true | false | testing | +| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | true | gateway api | +| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | true | service mesh | +| **ingress** | Ingress | annotation,label | all,single | true | false | true | kubernetes core | +| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | true | service mesh | +| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | true | service mesh | +| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | true | ingress controllers | +| **node** | Node | annotation,label | all | true | false | false | kubernetes core | +| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | true | openshift | +| **pod** | Pod | annotation,label | all,single | true | false | false | kubernetes core | +| **service** | Service | annotation,label | all,single | true | false | true | kubernetes core | +| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | true | ingress controllers | +| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | true | ingress controllers | ## Usage diff --git a/internal/gen/docs/sources/main.go b/internal/gen/docs/sources/main.go index 13de9ad954..69bc255fcc 100644 --- a/internal/gen/docs/sources/main.go +++ b/internal/gen/docs/sources/main.go @@ -41,8 +41,9 @@ const ( annotationResources = annotationPrefix + "resources=" annotationFilters = annotationPrefix + "filters=" annotationNamespace = annotationPrefix + "namespace=" - annotationFQDNTemplate = annotationPrefix + "fqdn-template=" - annotationEvents = annotationPrefix + "events=" + annotationFQDNTemplate = annotationPrefix + "fqdn-template=" + annotationEvents = annotationPrefix + "events=" + annotationProviderSpecific = annotationPrefix + "provider-specific=" ) var ( @@ -62,8 +63,9 @@ type Source struct { Resources string // Kubernetes resources watched, e.g., "Service", "Ingress" Filters string // Supported filters, e.g., "annotation,label" Namespace string // Namespace support: "all", "single", "multiple" - FQDNTemplate string // FQDN template support: "true", "false" - Events string // Events support: "true", "false" + FQDNTemplate string // FQDN template support: "true", "false" + Events string // Events support: "true", "false" + ProviderSpecific string // Provider-specific properties support: "true", "false" } type Sources []Source @@ -256,10 +258,11 @@ func extractSourcesFromComments(comments, typeName, filePath string) (Sources, e // Start new source currentSource = &Source{ - Type: typeName, - File: filePath, - Name: strings.TrimPrefix(line, annotationName), - Events: "false", + Type: typeName, + File: filePath, + Name: strings.TrimPrefix(line, annotationName), + Events: "false", + ProviderSpecific: "false", } case currentSource == nil: return nil, fmt.Errorf("found annotation line without preceding source name in type %s: %s", typeName, line) @@ -277,6 +280,8 @@ func extractSourcesFromComments(comments, typeName, filePath string) (Sources, e currentSource.FQDNTemplate = strings.TrimPrefix(line, annotationFQDNTemplate) case strings.HasPrefix(line, annotationEvents): currentSource.Events = strings.TrimPrefix(line, annotationEvents) + case strings.HasPrefix(line, annotationProviderSpecific): + currentSource.ProviderSpecific = strings.TrimPrefix(line, annotationProviderSpecific) } } diff --git a/internal/gen/docs/sources/main_test.go b/internal/gen/docs/sources/main_test.go index 3e58c2e8de..0c7fe3c85c 100644 --- a/internal/gen/docs/sources/main_test.go +++ b/internal/gen/docs/sources/main_test.go @@ -110,6 +110,7 @@ func TestParseSourceAnnotations(t *testing.T) { // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type testSource struct { client string } @@ -129,6 +130,7 @@ type testSource struct { assert.Equal(t, "all,single", source.Namespace) assert.Equal(t, "true", source.FQDNTemplate) assert.Equal(t, "false", source.Events) + assert.Equal(t, "true", source.ProviderSpecific) } func TestParseSourceAnnotations_SkipsTestFiles(t *testing.T) { @@ -180,8 +182,10 @@ type secondSource struct {} assert.Len(t, sources, 2) assert.Equal(t, "first", sources[0].Name) assert.Equal(t, "false", sources[0].Events) + assert.Equal(t, "false", sources[0].ProviderSpecific) assert.Equal(t, "second", sources[1].Name) assert.Equal(t, "true", sources[1].Events) + assert.Equal(t, "false", sources[1].ProviderSpecific) } func TestParseFile_IgnoresNonSourceTypes(t *testing.T) { diff --git a/internal/gen/docs/sources/templates/sources.gotpl b/internal/gen/docs/sources/templates/sources.gotpl index 486c72c53c..4634de29a4 100644 --- a/internal/gen/docs/sources/templates/sources.gotpl +++ b/internal/gen/docs/sources/templates/sources.gotpl @@ -22,10 +22,10 @@ Sources are responsible for: ## Available Sources -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Category | -|:----------------|:----------|:--------|:----------|:--------------|:---------|:---------| +| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | +|:----------------|:----------|:--------|:----------|:--------------|:---------|:------------------|:---------| {{- range . }} -| **{{ .Name }}** | {{ replace .Resources "," "
" }} | {{ .Filters }} | {{ .Namespace }} | {{ .FQDNTemplate }} | {{ .Events }} | {{ lower .Category }} | +| **{{ .Name }}** | {{ replace .Resources "," "
" }} | {{ .Filters }} | {{ .Namespace }} | {{ .FQDNTemplate }} | {{ .Events }} | {{ .ProviderSpecific }} | {{ lower .Category }} | {{- end }} ## Usage diff --git a/source/ambassador_host.go b/source/ambassador_host.go index 76bad3f770..8685f10c1f 100644 --- a/source/ambassador_host.go +++ b/source/ambassador_host.go @@ -66,6 +66,7 @@ var ( // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false // +externaldns:source:events=false +// +externaldns:source:provider-specific=true type ambassadorHostSource struct { dynamicKubeClient dynamic.Interface kubeClient kubernetes.Interface diff --git a/source/connector.go b/source/connector.go index 223b8c4f7c..47cb9b1483 100644 --- a/source/connector.go +++ b/source/connector.go @@ -41,6 +41,7 @@ const ( // +externaldns:source:filters= // +externaldns:source:namespace= // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=false type connectorSource struct { remoteServer string } diff --git a/source/contour_httpproxy.go b/source/contour_httpproxy.go index a98315c78b..d1cc2e8f19 100644 --- a/source/contour_httpproxy.go +++ b/source/contour_httpproxy.go @@ -49,6 +49,7 @@ import ( // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type httpProxySource struct { dynamicKubeClient dynamic.Interface namespace string diff --git a/source/crd.go b/source/crd.go index d11a182d17..cd33f1e893 100644 --- a/source/crd.go +++ b/source/crd.go @@ -53,6 +53,7 @@ import ( // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false // +externaldns:source:events=false +// +externaldns:source:provider-specific=false type crdSource struct { crdClient rest.Interface namespace string diff --git a/source/empty.go b/source/empty.go index 687478d7e6..9f2abdd1fa 100644 --- a/source/empty.go +++ b/source/empty.go @@ -31,6 +31,7 @@ import ( // +externaldns:source:filters= // +externaldns:source:namespace= // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=false type emptySource struct{} func (e *emptySource) AddEventHandler(_ context.Context, _ func()) { diff --git a/source/f5_transportserver.go b/source/f5_transportserver.go index 781b50fc29..01a9bc160a 100644 --- a/source/f5_transportserver.go +++ b/source/f5_transportserver.go @@ -55,6 +55,7 @@ var f5TransportServerGVR = schema.GroupVersionResource{ // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=false type f5TransportServerSource struct { dynamicKubeClient dynamic.Interface transportServerInformer kubeinformers.GenericInformer diff --git a/source/f5_virtualserver.go b/source/f5_virtualserver.go index c70a4b6ddc..fc4f4889c3 100644 --- a/source/f5_virtualserver.go +++ b/source/f5_virtualserver.go @@ -54,6 +54,7 @@ var f5VirtualServerGVR = schema.GroupVersionResource{ // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=false type f5VirtualServerSource struct { dynamicKubeClient dynamic.Interface virtualServerInformer kubeinformers.GenericInformer diff --git a/source/fake.go b/source/fake.go index f6f12a135b..f331cc00bc 100644 --- a/source/fake.go +++ b/source/fake.go @@ -45,6 +45,7 @@ import ( // +externaldns:source:namespace= // +externaldns:source:fqdn-template=true // +externaldns:source:events=true +// +externaldns:source:provider-specific=false type fakeSource struct { dnsName string } diff --git a/source/gateway.go b/source/gateway.go index 03d0e57ba6..0076194f46 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -96,6 +96,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-grpcroute // +externaldns:source:category=Gateway API @@ -104,6 +105,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-tcproute // +externaldns:source:category=Gateway API @@ -112,6 +114,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-tlsroute // +externaldns:source:category=Gateway API @@ -120,6 +123,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-udproute // +externaldns:source:category=Gateway API @@ -128,6 +132,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type gatewayRouteSource struct { gwName string gwNamespace string diff --git a/source/gloo_proxy.go b/source/gloo_proxy.go index e7352eec37..1100ffb7e3 100644 --- a/source/gloo_proxy.go +++ b/source/gloo_proxy.go @@ -134,6 +134,7 @@ type proxyVirtualHostMetadataSourceResourceRef struct { // +externaldns:source:filters= // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true type glooSource struct { serviceInformer coreinformers.ServiceInformer ingressInformer netinformers.IngressInformer diff --git a/source/ingress.go b/source/ingress.go index a5c3784ad7..097b4627fb 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -60,6 +60,7 @@ const ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type ingressSource struct { client kubernetes.Interface namespace string diff --git a/source/istio_gateway.go b/source/istio_gateway.go index 94ead3b0fd..42be64ba28 100644 --- a/source/istio_gateway.go +++ b/source/istio_gateway.go @@ -58,6 +58,7 @@ var IstioGatewayIngressSource = annotations.Ingress // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type gatewaySource struct { kubeClient kubernetes.Interface istioClient istioclient.Interface diff --git a/source/istio_virtualservice.go b/source/istio_virtualservice.go index ba634bfca5..a8c1805ec4 100644 --- a/source/istio_virtualservice.go +++ b/source/istio_virtualservice.go @@ -59,6 +59,7 @@ const IstioMeshGateway = "mesh" // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type virtualServiceSource struct { kubeClient kubernetes.Interface istioClient istioclient.Interface diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go index 988fb34d11..2895c42ca0 100644 --- a/source/kong_tcpingress.go +++ b/source/kong_tcpingress.go @@ -56,6 +56,7 @@ var kongGroupdVersionResource = schema.GroupVersionResource{ // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true type kongTCPIngressSource struct { annotationFilter string ignoreHostnameAnnotation bool diff --git a/source/node.go b/source/node.go index 4c6ba02ddd..45d3eac448 100644 --- a/source/node.go +++ b/source/node.go @@ -45,6 +45,7 @@ import ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=false type nodeSource struct { client kubernetes.Interface annotationFilter string diff --git a/source/openshift_route.go b/source/openshift_route.go index 9582dd485a..c029d34565 100644 --- a/source/openshift_route.go +++ b/source/openshift_route.go @@ -51,6 +51,7 @@ import ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type ocpRouteSource struct { client versioned.Interface namespace string diff --git a/source/pod.go b/source/pod.go index 0e96e029c4..cd11ae832d 100644 --- a/source/pod.go +++ b/source/pod.go @@ -45,6 +45,7 @@ import ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=false type podSource struct { client kubernetes.Interface namespace string diff --git a/source/service.go b/source/service.go index 4fd8c31193..26a8febb32 100644 --- a/source/service.go +++ b/source/service.go @@ -70,6 +70,7 @@ var ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type serviceSource struct { client kubernetes.Interface namespace string diff --git a/source/skipper_routegroup.go b/source/skipper_routegroup.go index 08e9a5497b..a23e9a02fd 100644 --- a/source/skipper_routegroup.go +++ b/source/skipper_routegroup.go @@ -57,6 +57,7 @@ const ( // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=true type routeGroupSource struct { cli routeGroupListClient apiServer string diff --git a/source/traefik_proxy.go b/source/traefik_proxy.go index 3bde81ed40..0d54c4fc12 100644 --- a/source/traefik_proxy.go +++ b/source/traefik_proxy.go @@ -88,6 +88,7 @@ var ( // +externaldns:source:filters=annotation // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false +// +externaldns:source:provider-specific=true type traefikSource struct { dynamicKubeClient dynamic.Interface kubeClient kubernetes.Interface From cdc1e0bfc279bb2aace08c9dd8148329278af88c Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 27 Feb 2026 12:09:08 +0000 Subject: [PATCH 02/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- internal/gen/docs/sources/main.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/gen/docs/sources/main.go b/internal/gen/docs/sources/main.go index 69bc255fcc..23f7abb311 100644 --- a/internal/gen/docs/sources/main.go +++ b/internal/gen/docs/sources/main.go @@ -34,13 +34,13 @@ import ( ) const ( - annotationPrefix = "+externaldns:source:" - annotationName = annotationPrefix + "name=" - annotationCategory = annotationPrefix + "category=" - annotationDesc = annotationPrefix + "description=" - annotationResources = annotationPrefix + "resources=" - annotationFilters = annotationPrefix + "filters=" - annotationNamespace = annotationPrefix + "namespace=" + annotationPrefix = "+externaldns:source:" + annotationName = annotationPrefix + "name=" + annotationCategory = annotationPrefix + "category=" + annotationDesc = annotationPrefix + "description=" + annotationResources = annotationPrefix + "resources=" + annotationFilters = annotationPrefix + "filters=" + annotationNamespace = annotationPrefix + "namespace=" annotationFQDNTemplate = annotationPrefix + "fqdn-template=" annotationEvents = annotationPrefix + "events=" annotationProviderSpecific = annotationPrefix + "provider-specific=" @@ -55,14 +55,14 @@ var ( // Source represents metadata about a source implementation type Source struct { - Name string // e.g., "service", "ingress", "crd" - Type string // e.g., "serviceSource" - File string // e.g., "source/service.go" - Description string // Description of what this source does - Category string // e.g., "Kubernetes", "Gateway", "Service Mesh", "Wrapper" - Resources string // Kubernetes resources watched, e.g., "Service", "Ingress" - Filters string // Supported filters, e.g., "annotation,label" - Namespace string // Namespace support: "all", "single", "multiple" + Name string // e.g., "service", "ingress", "crd" + Type string // e.g., "serviceSource" + File string // e.g., "source/service.go" + Description string // Description of what this source does + Category string // e.g., "Kubernetes", "Gateway", "Service Mesh", "Wrapper" + Resources string // Kubernetes resources watched, e.g., "Service", "Ingress" + Filters string // Supported filters, e.g., "annotation,label" + Namespace string // Namespace support: "all", "single", "multiple" FQDNTemplate string // FQDN template support: "true", "false" Events string // Events support: "true", "false" ProviderSpecific string // Provider-specific properties support: "true", "false" From f37beeca4a000a0f9697e53dcb0311324717fe97 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 27 Feb 2026 13:06:11 +0000 Subject: [PATCH 03/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 2 +- source/contour_httpproxy_test.go | 22 +++++++++++++++ source/crd.go | 2 +- source/crd_test.go | 24 +++++++++++++++++ source/f5_transportserver_test.go | 35 ++++++++++++++++++++++++ source/f5_virtualserver_test.go | 35 ++++++++++++++++++++++++ source/istio_gateway_test.go | 26 ++++++++++++++++++ source/istio_virtualservice_test.go | 29 ++++++++++++++++++++ source/kong_tcpingress_test.go | 42 +++++++++++++++++++++++++++++ source/node_test.go | 12 +++++++++ source/openshift_route_test.go | 37 +++++++++++++++++++++++++ source/pod_test.go | 31 +++++++++++++++++++++ source/service_test.go | 24 +++++++++++++++++ source/skipper_routegroup_test.go | 27 +++++++++++++++++++ source/traefik_proxy_test.go | 34 +++++++++++++++++++++++ 15 files changed, 380 insertions(+), 2 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 1e3d646133..2c2082ed15 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -27,7 +27,7 @@ Sources are responsible for: | **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | | **connector** | Remote TCP Server | | | false | false | false | special | | **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | false | false | externaldns | +| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | false | true | externaldns | | **empty** | None | | | false | false | false | testing | | **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | | **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | diff --git a/source/contour_httpproxy_test.go b/source/contour_httpproxy_test.go index 2422c277e8..6baf6dad12 100644 --- a/source/contour_httpproxy_test.go +++ b/source/contour_httpproxy_test.go @@ -283,6 +283,28 @@ func testEndpointsFromHTTPProxy(t *testing.T) { }, expected: []*endpoint.Endpoint{}, }, + { + title: "provider-specific annotation is converted to endpoint property", + httpProxy: fakeHTTPProxy{ + host: "foo.bar", + annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + loadBalancer: fakeLoadBalancerService{ + ips: []string{"8.8.8.8"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(ti.title, func(t *testing.T) { diff --git a/source/crd.go b/source/crd.go index cd33f1e893..76ced6bbc8 100644 --- a/source/crd.go +++ b/source/crd.go @@ -53,7 +53,7 @@ import ( // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false // +externaldns:source:events=false -// +externaldns:source:provider-specific=false +// +externaldns:source:provider-specific=true type crdSource struct { crdClient rest.Interface namespace string diff --git a/source/crd_test.go b/source/crd_test.go index 719d463ea6..cc8b60fd44 100644 --- a/source/crd_test.go +++ b/source/crd_test.go @@ -582,6 +582,30 @@ func testCRDSourceEndpoints(t *testing.T) { expectEndpoints: true, expectError: false, }, + { + title: "provider-specific properties are passed through from DNSEndpoint spec", + registeredAPIVersion: apiv1alpha1.GroupVersion.String(), + apiVersion: apiv1alpha1.GroupVersion.String(), + registeredKind: apiv1alpha1.DNSEndpointKind, + kind: apiv1alpha1.DNSEndpointKind, + namespace: "foo", + registeredNamespace: "foo", + endpoints: []*endpoint.Endpoint{ + { + DNSName: "subdomain.example.org", + Targets: endpoint.Targets{"other.example.org"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 180, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/failover", Value: "PRIMARY"}, + {Name: "aws/health-check-id", Value: "asdf1234-as12-as12-as12-asdf12345678"}, + {Name: "aws/evaluate-target-health", Value: "true"}, + }, + SetIdentifier: "some-unique-id", + }, + }, + expectEndpoints: true, + }, } { t.Run(ti.title, func(t *testing.T) { t.Parallel() diff --git a/source/f5_transportserver_test.go b/source/f5_transportserver_test.go index 4418cefeed..839905a210 100644 --- a/source/f5_transportserver_test.go +++ b/source/f5_transportserver_test.go @@ -326,6 +326,41 @@ func TestF5TransportServerEndpoints(t *testing.T) { }, expected: nil, }, + { + name: "F5 TransportServer does not support provider-specific annotations", + transportServer: f5.TransportServer{ + TypeMeta: metav1.TypeMeta{ + APIVersion: f5TransportServerGVR.GroupVersion().String(), + Kind: "TransportServer", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vs", + Namespace: defaultF5TransportServerNamespace, + Annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + }, + Spec: f5.TransportServerSpec{ + Host: "www.example.com", + VirtualServerAddress: "192.168.1.100", + }, + Status: f5.CustomResourceStatus{ + VSAddress: "192.168.1.100", + Status: "OK", + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "www.example.com", + Targets: []string{"192.168.1.100"}, + RecordType: endpoint.RecordTypeA, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "f5-transportserver/transportserver/test-vs", + }, + }, + }, + }, } for _, tc := range tests { diff --git a/source/f5_virtualserver_test.go b/source/f5_virtualserver_test.go index eb05bd8cf0..aeeaa8fa0c 100644 --- a/source/f5_virtualserver_test.go +++ b/source/f5_virtualserver_test.go @@ -568,6 +568,41 @@ func TestF5VirtualServerEndpoints(t *testing.T) { }, }, }, + { + name: "F5 VirtualServer does not support provider-specific annotations", + virtualServer: f5.VirtualServer{ + TypeMeta: metav1.TypeMeta{ + APIVersion: f5VirtualServerGVR.GroupVersion().String(), + Kind: "VirtualServer", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vs", + Namespace: defaultF5VirtualServerNamespace, + Annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + }, + Spec: f5.VirtualServerSpec{ + Host: "www.example.com", + VirtualServerAddress: "192.168.1.100", + }, + Status: f5.CustomResourceStatus{ + VSAddress: "192.168.1.100", + Status: "OK", + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "www.example.com", + Targets: []string{"192.168.1.100"}, + RecordType: endpoint.RecordTypeA, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "f5-virtualserver/virtualserver/test-vs", + }, + }, + }, + }, } for _, tc := range tests { diff --git a/source/istio_gateway_test.go b/source/istio_gateway_test.go index 33989de89f..4b93301e4d 100644 --- a/source/istio_gateway_test.go +++ b/source/istio_gateway_test.go @@ -496,6 +496,32 @@ func testEndpointsFromGatewayConfig(t *testing.T) { }, }, }, + { + title: "provider-specific annotation is converted to endpoint property", + lbServices: []fakeIngressGatewayService{ + { + ips: []string{"8.8.8.8"}, + }, + }, + config: fakeGatewayConfig{ + annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + dnsnames: [][]string{ + {"foo.bar"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(ti.title, func(t *testing.T) { diff --git a/source/istio_virtualservice_test.go b/source/istio_virtualservice_test.go index f7efed5647..f31404c62a 100644 --- a/source/istio_virtualservice_test.go +++ b/source/istio_virtualservice_test.go @@ -695,6 +695,35 @@ func testEndpointsFromVirtualServiceConfig(t *testing.T) { }, }, }, + { + title: "provider-specific annotation is converted to endpoint property", + lbServices: []fakeIngressGatewayService{ + { + ips: []string{"8.8.8.8"}, + }, + }, + gwconfig: fakeGatewayConfig{ + name: "mygw", + dnsnames: [][]string{{"*"}}, + }, + vsconfig: fakeVirtualServiceConfig{ + annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + gateways: []string{"mygw"}, + dnsnames: []string{"foo.bar"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(ti.title, func(t *testing.T) { diff --git a/source/kong_tcpingress_test.go b/source/kong_tcpingress_test.go index 9c99339940..3c27c5799d 100644 --- a/source/kong_tcpingress_test.go +++ b/source/kong_tcpingress_test.go @@ -30,6 +30,7 @@ import ( fakeKube "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/annotations" ) // This is a compile-time validation that kongTCPIngressSource is a Source. @@ -342,6 +343,47 @@ func TestKongTCPIngressEndpoints(t *testing.T) { }, }, }, + { + title: "TCPIngress with provider-specific annotation", + tcpProxy: TCPIngress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kongGroupdVersionResource.GroupVersion().String(), + Kind: "TCPIngress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-ingress-provider-specific", + Namespace: defaultKongNamespace, + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/hostname": "a.example.com", + "kubernetes.io/ingress.class": "kong", + annotations.AWSPrefix + "weight": "10", + }, + }, + Status: tcpIngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "1.2.3.4", + }, + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "a.example.com", + Targets: []string{"1.2.3.4"}, + RecordType: endpoint.RecordTypeA, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-provider-specific", + }, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(ti.title, func(t *testing.T) { diff --git a/source/node_test.go b/source/node_test.go index 8a795d1802..4d2d93bc8f 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -403,6 +403,18 @@ func testNodeSourceEndpoints(t *testing.T) { "Skipping node node1 because it is unschedulable", }, }, + { + title: "provider-specific annotation is not supported and is ignored", + nodeName: "node1", + exposeInternalIPv6: true, + nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}}, + annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + expected: []*endpoint.Endpoint{ + {RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}}, + }, + }, } { t.Run(tc.title, func(t *testing.T) { hook := testutils.LogsUnderTestWithLogLevel(log.DebugLevel, t) diff --git a/source/openshift_route_test.go b/source/openshift_route_test.go index d9b1a9b578..4d899a4374 100644 --- a/source/openshift_route_test.go +++ b/source/openshift_route_test.go @@ -31,6 +31,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/annotations" ) type OCPRouteSuite struct { @@ -515,6 +516,42 @@ func testOcpRouteSourceEndpoints(t *testing.T) { }, expected: []*endpoint.Endpoint{}, }, + { + title: "route with provider-specific annotation", + ocpRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "route-with-provider-specific", + Annotations: map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + }, + Status: routev1.RouteStatus{ + Ingress: []routev1.RouteIngress{ + { + Host: "my-domain.com", + RouterCanonicalHostname: "apps.my-domain.com", + Conditions: []routev1.RouteIngressCondition{ + { + Type: routev1.RouteAdmitted, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "my-domain.com", + RecordType: endpoint.RecordTypeCNAME, + Targets: []string{"apps.my-domain.com"}, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(tc.title, func(t *testing.T) { diff --git a/source/pod_test.go b/source/pod_test.go index 34631ec538..57750b8469 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -642,6 +642,37 @@ func TestPodSource(t *testing.T) { }, }, }, + { + "provider-specific annotation is not supported and is ignored", + "", + "", + true, + "", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, + }, + false, + nodesFixturesIPv4(), + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + annotations.HostnameKey: "a.foo.example.org", + annotations.AWSPrefix + "weight": "10", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + }, + }, } { t.Run(tc.title, func(t *testing.T) { kubernetes := fake.NewClientset() diff --git a/source/service_test.go b/source/service_test.go index 84e1345709..2e2b3c16eb 100644 --- a/source/service_test.go +++ b/source/service_test.go @@ -1095,6 +1095,30 @@ func testServiceSourceEndpoints(t *testing.T) { {DNSName: "foobar-v6.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::2"}}, }, }, + { + title: "provider-specific annotation is converted to endpoint property", + svcNamespace: "testing", + svcName: "foo", + svcType: v1.ServiceTypeLoadBalancer, + labels: map[string]string{}, + externalIPs: []string{}, + lbs: []string{"1.2.3.4"}, + serviceTypesFilter: []string{string(v1.ServiceTypeLoadBalancer)}, + annotations: map[string]string{ + annotations.HostnameKey: "foo.example.org", + annotations.AWSPrefix + "weight": "10", + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.example.org", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(tc.title, func(t *testing.T) { diff --git a/source/skipper_routegroup_test.go b/source/skipper_routegroup_test.go index bd59401aab..9c1ce4f7ca 100644 --- a/source/skipper_routegroup_test.go +++ b/source/skipper_routegroup_test.go @@ -276,6 +276,33 @@ func TestEndpointsFromRouteGroups(t *testing.T) { }, }, }, + { + name: "Routegroup with provider-specific annotation creates endpoint with provider-specific property", + source: &routeGroupSource{}, + rg: createTestRouteGroup( + "namespace1", + "rg1", + map[string]string{ + annotations.AWSPrefix + "weight": "10", + }, + []string{"rg1.k8s.example"}, + []routeGroupLoadBalancer{ + { + Hostname: "lb.example.org", + }, + }, + ), + want: []*endpoint.Endpoint{ + { + DNSName: "rg1.k8s.example", + RecordType: endpoint.RecordTypeCNAME, + Targets: endpoint.Targets([]string{"lb.example.org"}), + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(tt.name, func(t *testing.T) { got := tt.source.endpointsFromRouteGroup(tt.rg) diff --git a/source/traefik_proxy_test.go b/source/traefik_proxy_test.go index 9b7f8946c9..d7ac7e45a4 100644 --- a/source/traefik_proxy_test.go +++ b/source/traefik_proxy_test.go @@ -35,6 +35,7 @@ import ( fakeKube "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/annotations" ) // This is a compile-time validation that traefikSource is a Source. @@ -329,6 +330,39 @@ func TestTraefikProxyIngressRouteEndpoints(t *testing.T) { }, expected: nil, }, + { + title: "IngressRoute with provider-specific annotation", + ingressRoute: IngressRoute{ + TypeMeta: metav1.TypeMeta{ + APIVersion: ingressRouteGVR.GroupVersion().String(), + Kind: "IngressRoute", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "ingressroute-provider-specific", + Namespace: defaultTraefikNamespace, + Annotations: map[string]string{ + annotations.HostnameKey: "a.example.com", + annotations.TargetKey: "target.domain.tld", + "kubernetes.io/ingress.class": "traefik", + annotations.AWSPrefix + "weight": "10", + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "a.example.com", + Targets: []string{"target.domain.tld"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "ingressroute/traefik/ingressroute-provider-specific", + }, + ProviderSpecific: endpoint.ProviderSpecific{ + {Name: "aws/weight", Value: "10"}, + }, + }, + }, + }, } { t.Run(ti.title, func(t *testing.T) { t.Parallel() From dc07dab72c0ffb6362b5a6dea6be9c1909a624dc Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 13 Mar 2026 06:49:11 +0000 Subject: [PATCH 04/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- source/unstructured.go | 1 + 1 file changed, 1 insertion(+) diff --git a/source/unstructured.go b/source/unstructured.go index 74c908ac9d..f3d2def264 100644 --- a/source/unstructured.go +++ b/source/unstructured.go @@ -53,6 +53,7 @@ import ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=true +// +externaldns:source:provider-specific=false type unstructuredSource struct { combineFqdnAnnotation bool fqdnTemplate *template.Template From 3f104ec8a6a552d81361c4acb8d2a698b9a87ce1 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 13 Mar 2026 07:03:05 +0000 Subject: [PATCH 05/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- source/unstructured_test.go | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/source/unstructured_test.go b/source/unstructured_test.go index 85fa13641a..d90d148329 100644 --- a/source/unstructured_test.go +++ b/source/unstructured_test.go @@ -405,6 +405,44 @@ func TestUnstructured_DifferentScenarios(t *testing.T) { WithLabel(endpoint.ResourceLabelKey, "virtualmachineinstance/default/prod-platform-vm"), }, }, + { + title: "provider-specific annotation is not supported and is ignored", + cfg: cfg{ + resources: []string{"machines.v1beta1.cluster.x-k8s.io"}, + }, + objects: []*unstructured.Unstructured{ + { + Object: map[string]any{ + "apiVersion": "cluster.x-k8s.io/v1beta1", + "kind": "Machine", + "metadata": map[string]any{ + "name": "control-plane", + "namespace": "default", + "labels": map[string]any{ + "cluster.x-k8s.io/cluster-name": "test-cluster", + "cluster.x-k8s.io/control-plane": "", + }, + "annotations": map[string]any{ + annotations.HostnameKey: "control-plane.example.com", + annotations.TargetKey: "10.0.0.1", + annotations.CloudflarePrefix: "cloudflare-specific-annotation", + }, + }, + "spec": map[string]any{ + "clusterName": "test-cluster", + "bootstrap": map[string]any{ + "dataSecretName": "control-plane-bootstrap", + }, + "version": "v1.26.0", + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + endpoint.NewEndpoint("control-plane.example.com", endpoint.RecordTypeA, "10.0.0.1"). + WithLabel(endpoint.ResourceLabelKey, "machine/default/control-plane"), + }, + }, } { t.Run(tt.title, func(t *testing.T) { kubeClient, dynamicClient := setupUnstructuredTestClients(t, tt.cfg.resources, tt.objects) From 0e52a2c474aef96b0fe5041dd729aeb340e008f5 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Mon, 16 Mar 2026 08:33:22 +0000 Subject: [PATCH 06/10] docs(sources): surface provider-specific annotations support it in source documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index e79b8de0e1..b73c977540 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -38,44 +38,17 @@ Sources are responsible for: | **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | | **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | true | gateway api | | **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | true | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | false | true | kubernetes core | +| **ingress** | Ingress | annotation,label | all,single | true | true | true | kubernetes core | | **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | true | service mesh | | **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | true | service mesh | | **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | true | ingress controllers | -| **node** | Node | annotation,label | all | true | false | false | kubernetes core | +| **node** | Node | annotation,label | all | true | true | false | kubernetes core | | **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | true | openshift | -| **pod** | Pod | annotation,label | all,single | true | false | false | kubernetes core | -| **service** | Service | annotation,label | all,single | true | false | true | kubernetes core | +| **pod** | Pod | annotation,label | all,single | true | true | false | kubernetes core | +| **service** | Service | annotation,label | all,single | true | true | true | kubernetes core | | **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | true | ingress controllers | | **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | true | ingress controllers | | **unstructured** | Unstructured | annotation,label | all,single | true | false | false | custom resources | -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Category | -|:----------------|:----------|:--------|:----------|:--------------|:---------|:---------| -| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | ingress controllers | -| **connector** | Remote TCP Server | | | false | false | special | -| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | externaldns | -| **empty** | None | | | false | false | testing | -| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **fake** | Fake Endpoints | | | true | true | testing | -| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | gateway api | -| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | true | kubernetes core | -| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | service mesh | -| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | service mesh | -| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | ingress controllers | -| **node** | Node | annotation,label | all | true | true | kubernetes core | -| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | openshift | -| **pod** | Pod | annotation,label | all,single | true | true | kubernetes core | -| **service** | Service | annotation,label | all,single | true | true | kubernetes core | -| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | ingress controllers | -| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | ingress controllers | -| **unstructured** | Unstructured | annotation,label | all,single | true | false | custom resources | ## Usage From 497b3f62bcef62c758bd0056bd879fc425ff4685 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Tue, 17 Mar 2026 07:49:11 +0000 Subject: [PATCH 07/10] docs(sources): surface provider-specific annotations support in documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 2 +- source/crd.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index b73c977540..16209eb59b 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -27,7 +27,7 @@ Sources are responsible for: | **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | | **connector** | Remote TCP Server | | | false | false | false | special | | **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | false | true | externaldns | +| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | true | externaldns | | **empty** | None | | | false | false | false | testing | | **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | | **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | diff --git a/source/crd.go b/source/crd.go index e1956f7736..336a0293dc 100644 --- a/source/crd.go +++ b/source/crd.go @@ -55,7 +55,7 @@ import ( // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single // +externaldns:source:fqdn-template=false -// +externaldns:source:events=false +// +externaldns:source:events=true // +externaldns:source:provider-specific=true type crdSource struct { crdClient rest.Interface From f2f8e69028dbb1fb7a1e07a90f6f94c172b355ba Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Wed, 18 Mar 2026 23:01:16 +0000 Subject: [PATCH 08/10] docs(sources): surface provider-specific annotations support in documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 81 +++++++------------ internal/gen/docs/sources/main.go | 32 ++++---- .../gen/docs/sources/templates/sources.gotpl | 10 +-- 3 files changed, 48 insertions(+), 75 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 8b93cee180..f63471d7c8 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -22,60 +22,33 @@ Sources are responsible for: ## Available Sources -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | -|:----------------|:----------|:--------|:----------|:--------------|:---------|:------------------|:---------| -| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | -| **connector** | Remote TCP Server | | | false | false | false | special | -| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | true | externaldns | -| **empty** | None | | | false | false | false | testing | -| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | -| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | -| **fake** | Fake Endpoints | | | true | true | false | testing | -| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | true | gateway api | -| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | true | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | true | true | kubernetes core | -| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | true | service mesh | -| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | true | service mesh | -| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | true | ingress controllers | -| **node** | Node | annotation,label | all | true | true | false | kubernetes core | -| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | true | openshift | -| **pod** | Pod | annotation,label | all,single | true | true | false | kubernetes core | -| **service** | Service | annotation,label | all,single | true | true | true | kubernetes core | -| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | true | ingress controllers | -| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | true | ingress controllers | -| **unstructured** | Unstructured | annotation,label | all,single | true | false | false | custom resources | -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Category | -|:-------------------------|:--------------------------------------------------------------------------------------|:-----------------|:-----------|:--------------|:-------|:--------------------| -| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | ingress controllers | -| **connector** | Remote TCP Server | | | false | false | special | -| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | externaldns | -| **empty** | None | | | false | false | testing | -| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | load balancers | -| **fake** | Fake Endpoints | | | true | true | testing | -| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | gateway api | -| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | gateway api | -| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | true | kubernetes core | -| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | service mesh | -| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | service mesh | -| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | ingress controllers | -| **node** | Node | annotation,label | all | true | true | kubernetes core | -| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | openshift | -| **pod** | Pod | annotation,label | all,single | true | true | kubernetes core | -| **service** | Service | annotation,label | all,single | true | true | kubernetes core | -| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | ingress controllers | -| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | ingress controllers | -| **unstructured** | Unstructured | annotation,label | all,single | true | false | custom resources | +| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | +|:-------------------------|:--------------------------------------------------------------------------------------|:-----------------|:-----------|:--------------|:-------|:------------------|:--------------------| +| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | +| **connector** | Remote TCP Server | | | false | false | false | special | +| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | +| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | true | externaldns | +| **empty** | None | | | false | false | false | testing | +| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | +| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | +| **fake** | Fake Endpoints | | | true | true | false | testing | +| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | +| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | true | gateway api | +| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | true | service mesh | +| **ingress** | Ingress | annotation,label | all,single | true | true | true | kubernetes core | +| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | true | service mesh | +| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | true | service mesh | +| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | true | ingress controllers | +| **node** | Node | annotation,label | all | true | true | false | kubernetes core | +| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | true | openshift | +| **pod** | Pod | annotation,label | all,single | true | true | false | kubernetes core | +| **service** | Service | annotation,label | all,single | true | true | true | kubernetes core | +| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | true | ingress controllers | +| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | true | ingress controllers | +| **unstructured** | Unstructured | annotation,label | all,single | true | false | false | custom resources | ## Usage diff --git a/internal/gen/docs/sources/main.go b/internal/gen/docs/sources/main.go index b77b562c39..37d5edc660 100644 --- a/internal/gen/docs/sources/main.go +++ b/internal/gen/docs/sources/main.go @@ -109,13 +109,14 @@ func discoverSources(dir string) (Sources, error) { } type sourceColumnWidths struct { - Name int - Resources int - Filters int - Namespace int - FQDNTemplate int - Events int - Category int + Name int + Resources int + Filters int + Namespace int + FQDNTemplate int + Events int + ProviderSpecific int + Category int } func computeSourceColumnWidths(sources Sources) sourceColumnWidths { @@ -126,6 +127,7 @@ func computeSourceColumnWidths(sources Sources) sourceColumnWidths { fqdnTemplates := make([]string, len(sources)) events := make([]string, len(sources)) categories := make([]string, len(sources)) + providerSpecifics := make([]string, len(sources)) for i, src := range sources { names[i] = "**" + src.Name + "**" resources[i] = strings.ReplaceAll(src.Resources, ",", "
") @@ -133,16 +135,18 @@ func computeSourceColumnWidths(sources Sources) sourceColumnWidths { namespaces[i] = src.Namespace fqdnTemplates[i] = src.FQDNTemplate events[i] = src.Events + providerSpecifics[i] = src.ProviderSpecific categories[i] = strings.ToLower(src.Category) } return sourceColumnWidths{ - Name: utils.ComputeColumnWidth("**Source Name**", names), - Resources: utils.ComputeColumnWidth("Resources", resources), - Filters: utils.ComputeColumnWidth("Filters", filters), - Namespace: utils.ComputeColumnWidth("Namespace", namespaces), - FQDNTemplate: utils.ComputeColumnWidth("FQDN Template", fqdnTemplates), - Events: utils.ComputeColumnWidth("Events", events), - Category: utils.ComputeColumnWidth("Category", categories), + Name: utils.ComputeColumnWidth("**Source Name**", names), + Resources: utils.ComputeColumnWidth("Resources", resources), + Filters: utils.ComputeColumnWidth("Filters", filters), + Namespace: utils.ComputeColumnWidth("Namespace", namespaces), + FQDNTemplate: utils.ComputeColumnWidth("FQDN Template", fqdnTemplates), + Events: utils.ComputeColumnWidth("Events", events), + ProviderSpecific: utils.ComputeColumnWidth("Provider Specific", providerSpecifics), + Category: utils.ComputeColumnWidth("Category", categories), } } diff --git a/internal/gen/docs/sources/templates/sources.gotpl b/internal/gen/docs/sources/templates/sources.gotpl index 089129e0b0..607c4866f2 100644 --- a/internal/gen/docs/sources/templates/sources.gotpl +++ b/internal/gen/docs/sources/templates/sources.gotpl @@ -22,14 +22,10 @@ Sources are responsible for: ## Available Sources -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | -|:----------------|:----------|:--------|:----------|:--------------|:---------|:------------------|:---------| -{{- range . }} -| **{{ .Name }}** | {{ replace .Resources "," "
" }} | {{ .Filters }} | {{ .Namespace }} | {{ .FQDNTemplate }} | {{ .Events }} | {{ .ProviderSpecific }} | {{ lower .Category }} | -| {{ padRight .ColWidths.Name "**Source Name**" }} | {{ padRight .ColWidths.Resources "Resources" }} | {{ padRight .ColWidths.Filters "Filters" }} | {{ padRight .ColWidths.Namespace "Namespace" }} | {{ padRight .ColWidths.FQDNTemplate "FQDN Template" }} | {{ padRight .ColWidths.Events "Events" }} | {{ padRight .ColWidths.Category "Category" }} | -|:{{ leftSep .ColWidths.Name }}|:{{ leftSep .ColWidths.Resources }}|:{{ leftSep .ColWidths.Filters }}|:{{ leftSep .ColWidths.Namespace }}|:{{ leftSep .ColWidths.FQDNTemplate }}|:{{ leftSep .ColWidths.Events }}|:{{ leftSep .ColWidths.Category }}| +| {{ padRight .ColWidths.Name "**Source Name**" }} | {{ padRight .ColWidths.Resources "Resources" }} | {{ padRight .ColWidths.Filters "Filters" }} | {{ padRight .ColWidths.Namespace "Namespace" }} | {{ padRight .ColWidths.FQDNTemplate "FQDN Template" }} | {{ padRight .ColWidths.Events "Events" }} | {{ padRight .ColWidths.ProviderSpecific "Provider Specific" }} | {{ padRight .ColWidths.Category "Category" }} | +|:{{ leftSep .ColWidths.Name }}|:{{ leftSep .ColWidths.Resources }}|:{{ leftSep .ColWidths.Filters }}|:{{ leftSep .ColWidths.Namespace }}|:{{ leftSep .ColWidths.FQDNTemplate }}|:{{ leftSep .ColWidths.Events }}|:{{ leftSep .ColWidths.ProviderSpecific }}|:{{ leftSep .ColWidths.Category }}| {{- range .Sources }} -| {{ padRight $.ColWidths.Name (.Name | bold) }} | {{ padRight $.ColWidths.Resources (replace .Resources "," "
") }} | {{ padRight $.ColWidths.Filters .Filters }} | {{ padRight $.ColWidths.Namespace .Namespace }} | {{ padRight $.ColWidths.FQDNTemplate .FQDNTemplate }} | {{ padRight $.ColWidths.Events .Events }} | {{ padRight $.ColWidths.Category (lower .Category) }} | +| {{ padRight $.ColWidths.Name (.Name | bold) }} | {{ padRight $.ColWidths.Resources (replace .Resources "," "
") }} | {{ padRight $.ColWidths.Filters .Filters }} | {{ padRight $.ColWidths.Namespace .Namespace }} | {{ padRight $.ColWidths.FQDNTemplate .FQDNTemplate }} | {{ padRight $.ColWidths.Events .Events }} | {{ padRight $.ColWidths.ProviderSpecific .ProviderSpecific }} | {{ padRight $.ColWidths.Category (lower .Category) }} | {{- end }} ## Usage From 1fe664e6a0024ad698e106803dd77352140843f5 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Wed, 18 Mar 2026 23:05:37 +0000 Subject: [PATCH 09/10] docs(sources): surface provider-specific annotations support in documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 54 +++++++++---------- .../gen/docs/sources/templates/sources.gotpl | 6 +-- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index f63471d7c8..47e69bca2d 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -22,33 +22,33 @@ Sources are responsible for: ## Available Sources -| **Source Name** | Resources | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | -|:-------------------------|:--------------------------------------------------------------------------------------|:-----------------|:-----------|:--------------|:-------|:------------------|:--------------------| -| **ambassador-host** | Host.getambassador.io | annotation,label | all,single | false | false | true | ingress controllers | -| **connector** | Remote TCP Server | | | false | false | false | special | -| **contour-httpproxy** | HTTPProxy.projectcontour.io | annotation | all,single | true | false | true | ingress controllers | -| **crd** | DNSEndpoint.externaldns.k8s.io | annotation,label | all,single | false | true | true | externaldns | -| **empty** | None | | | false | false | false | testing | -| **f5-transportserver** | TransportServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | -| **f5-virtualserver** | VirtualServer.cis.f5.com | annotation | all,single | false | false | false | load balancers | -| **fake** | Fake Endpoints | | | true | true | false | testing | -| **gateway-grpcroute** | GRPCRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-httproute** | HTTPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-tcproute** | TCPRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-tlsroute** | TLSRoute.gateway.networking.k8s.io | annotation,label | all,single | false | false | true | gateway api | -| **gateway-udproute** | UDPRoute.gateway.networking.k8s.io | annotation,label | all,single | true | false | true | gateway api | -| **gloo-proxy** | Proxy.gloo.solo.io | | all,single | false | false | true | service mesh | -| **ingress** | Ingress | annotation,label | all,single | true | true | true | kubernetes core | -| **istio-gateway** | Gateway.networking.istio.io | annotation | all,single | true | false | true | service mesh | -| **istio-virtualservice** | VirtualService.networking.istio.io | annotation | all,single | true | false | true | service mesh | -| **kong-tcpingress** | TCPIngress.configuration.konghq.com | annotation | all,single | false | false | true | ingress controllers | -| **node** | Node | annotation,label | all | true | true | false | kubernetes core | -| **openshift-route** | Route.route.openshift.io | annotation,label | all,single | true | false | true | openshift | -| **pod** | Pod | annotation,label | all,single | true | true | false | kubernetes core | -| **service** | Service | annotation,label | all,single | true | true | true | kubernetes core | -| **skipper-routegroup** | RouteGroup.zalando.org | annotation | all,single | true | false | true | ingress controllers | -| **traefik-proxy** | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | annotation | all,single | false | false | true | ingress controllers | -| **unstructured** | Unstructured | annotation,label | all,single | true | false | false | custom resources | +| **Source Name** | Filters | Namespace | FQDN Template | Events | Provider Specific | Category | Resources | +|:-------------------------|:-----------------|:-----------|:--------------|:-------|:------------------|:--------------------|:--------------------------------------------------------------------------------------| +| **ambassador-host** | annotation,label | all,single | false | false | true | ingress controllers | Host.getambassador.io | +| **connector** | | | false | false | false | special | Remote TCP Server | +| **contour-httpproxy** | annotation | all,single | true | false | true | ingress controllers | HTTPProxy.projectcontour.io | +| **crd** | annotation,label | all,single | false | true | true | externaldns | DNSEndpoint.externaldns.k8s.io | +| **empty** | | | false | false | false | testing | None | +| **f5-transportserver** | annotation | all,single | false | false | false | load balancers | TransportServer.cis.f5.com | +| **f5-virtualserver** | annotation | all,single | false | false | false | load balancers | VirtualServer.cis.f5.com | +| **fake** | | | true | true | false | testing | Fake Endpoints | +| **gateway-grpcroute** | annotation,label | all,single | false | false | true | gateway api | GRPCRoute.gateway.networking.k8s.io | +| **gateway-httproute** | annotation,label | all,single | false | false | true | gateway api | HTTPRoute.gateway.networking.k8s.io | +| **gateway-tcproute** | annotation,label | all,single | false | false | true | gateway api | TCPRoute.gateway.networking.k8s.io | +| **gateway-tlsroute** | annotation,label | all,single | false | false | true | gateway api | TLSRoute.gateway.networking.k8s.io | +| **gateway-udproute** | annotation,label | all,single | true | false | true | gateway api | UDPRoute.gateway.networking.k8s.io | +| **gloo-proxy** | | all,single | false | false | true | service mesh | Proxy.gloo.solo.io | +| **ingress** | annotation,label | all,single | true | true | true | kubernetes core | Ingress | +| **istio-gateway** | annotation | all,single | true | false | true | service mesh | Gateway.networking.istio.io | +| **istio-virtualservice** | annotation | all,single | true | false | true | service mesh | VirtualService.networking.istio.io | +| **kong-tcpingress** | annotation | all,single | false | false | true | ingress controllers | TCPIngress.configuration.konghq.com | +| **node** | annotation,label | all | true | true | false | kubernetes core | Node | +| **openshift-route** | annotation,label | all,single | true | false | true | openshift | Route.route.openshift.io | +| **pod** | annotation,label | all,single | true | true | false | kubernetes core | Pod | +| **service** | annotation,label | all,single | true | true | true | kubernetes core | Service | +| **skipper-routegroup** | annotation | all,single | true | false | true | ingress controllers | RouteGroup.zalando.org | +| **traefik-proxy** | annotation | all,single | false | false | true | ingress controllers | IngressRoute.traefik.io
IngressRouteTCP.traefik.io
IngressRouteUDP.traefik.io | +| **unstructured** | annotation,label | all,single | true | false | false | custom resources | Unstructured | ## Usage diff --git a/internal/gen/docs/sources/templates/sources.gotpl b/internal/gen/docs/sources/templates/sources.gotpl index 607c4866f2..ec99c7bdad 100644 --- a/internal/gen/docs/sources/templates/sources.gotpl +++ b/internal/gen/docs/sources/templates/sources.gotpl @@ -22,10 +22,10 @@ Sources are responsible for: ## Available Sources -| {{ padRight .ColWidths.Name "**Source Name**" }} | {{ padRight .ColWidths.Resources "Resources" }} | {{ padRight .ColWidths.Filters "Filters" }} | {{ padRight .ColWidths.Namespace "Namespace" }} | {{ padRight .ColWidths.FQDNTemplate "FQDN Template" }} | {{ padRight .ColWidths.Events "Events" }} | {{ padRight .ColWidths.ProviderSpecific "Provider Specific" }} | {{ padRight .ColWidths.Category "Category" }} | -|:{{ leftSep .ColWidths.Name }}|:{{ leftSep .ColWidths.Resources }}|:{{ leftSep .ColWidths.Filters }}|:{{ leftSep .ColWidths.Namespace }}|:{{ leftSep .ColWidths.FQDNTemplate }}|:{{ leftSep .ColWidths.Events }}|:{{ leftSep .ColWidths.ProviderSpecific }}|:{{ leftSep .ColWidths.Category }}| +| {{ padRight .ColWidths.Name "**Source Name**" }} | {{ padRight .ColWidths.Filters "Filters" }} | {{ padRight .ColWidths.Namespace "Namespace" }} | {{ padRight .ColWidths.FQDNTemplate "FQDN Template" }} | {{ padRight .ColWidths.Events "Events" }} | {{ padRight .ColWidths.ProviderSpecific "Provider Specific" }} | {{ padRight .ColWidths.Category "Category" }} | {{ padRight .ColWidths.Resources "Resources" }} | +|:{{ leftSep .ColWidths.Name }}|:{{ leftSep .ColWidths.Filters }}|:{{ leftSep .ColWidths.Namespace }}|:{{ leftSep .ColWidths.FQDNTemplate }}|:{{ leftSep .ColWidths.Events }}|:{{ leftSep .ColWidths.ProviderSpecific }}|:{{ leftSep .ColWidths.Category }}|:{{ leftSep .ColWidths.Resources }}| {{- range .Sources }} -| {{ padRight $.ColWidths.Name (.Name | bold) }} | {{ padRight $.ColWidths.Resources (replace .Resources "," "
") }} | {{ padRight $.ColWidths.Filters .Filters }} | {{ padRight $.ColWidths.Namespace .Namespace }} | {{ padRight $.ColWidths.FQDNTemplate .FQDNTemplate }} | {{ padRight $.ColWidths.Events .Events }} | {{ padRight $.ColWidths.ProviderSpecific .ProviderSpecific }} | {{ padRight $.ColWidths.Category (lower .Category) }} | +| {{ padRight $.ColWidths.Name (.Name | bold) }} | {{ padRight $.ColWidths.Filters .Filters }} | {{ padRight $.ColWidths.Namespace .Namespace }} | {{ padRight $.ColWidths.FQDNTemplate .FQDNTemplate }} | {{ padRight $.ColWidths.Events .Events }} | {{ padRight $.ColWidths.ProviderSpecific .ProviderSpecific }} | {{ padRight $.ColWidths.Category (lower .Category) }} | {{ padRight $.ColWidths.Resources (replace .Resources "," "
") }} | {{- end }} ## Usage From d87ae7766f9b2823158bbc76d546e24358c49d33 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Thu, 19 Mar 2026 08:15:46 +0000 Subject: [PATCH 10/10] docs(sources): surface provider-specific annotations support in documentation Signed-off-by: ivan katliarchuk --- docs/sources/index.md | 8 ++++---- source/gateway.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index 47e69bca2d..8a82fab9a0 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -32,10 +32,10 @@ Sources are responsible for: | **f5-transportserver** | annotation | all,single | false | false | false | load balancers | TransportServer.cis.f5.com | | **f5-virtualserver** | annotation | all,single | false | false | false | load balancers | VirtualServer.cis.f5.com | | **fake** | | | true | true | false | testing | Fake Endpoints | -| **gateway-grpcroute** | annotation,label | all,single | false | false | true | gateway api | GRPCRoute.gateway.networking.k8s.io | -| **gateway-httproute** | annotation,label | all,single | false | false | true | gateway api | HTTPRoute.gateway.networking.k8s.io | -| **gateway-tcproute** | annotation,label | all,single | false | false | true | gateway api | TCPRoute.gateway.networking.k8s.io | -| **gateway-tlsroute** | annotation,label | all,single | false | false | true | gateway api | TLSRoute.gateway.networking.k8s.io | +| **gateway-grpcroute** | annotation,label | all,single | true | false | true | gateway api | GRPCRoute.gateway.networking.k8s.io | +| **gateway-httproute** | annotation,label | all,single | true | false | true | gateway api | HTTPRoute.gateway.networking.k8s.io | +| **gateway-tcproute** | annotation,label | all,single | true | false | true | gateway api | TCPRoute.gateway.networking.k8s.io | +| **gateway-tlsroute** | annotation,label | all,single | true | false | true | gateway api | TLSRoute.gateway.networking.k8s.io | | **gateway-udproute** | annotation,label | all,single | true | false | true | gateway api | UDPRoute.gateway.networking.k8s.io | | **gloo-proxy** | | all,single | false | false | true | service mesh | Proxy.gloo.solo.io | | **ingress** | annotation,label | all,single | true | true | true | kubernetes core | Ingress | diff --git a/source/gateway.go b/source/gateway.go index a0800d5688..5b4bb02d0f 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -94,7 +94,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:resources=HTTPRoute.gateway.networking.k8s.io // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single -// +externaldns:source:fqdn-template=false +// +externaldns:source:fqdn-template=true // +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-grpcroute @@ -103,7 +103,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:resources=GRPCRoute.gateway.networking.k8s.io // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single -// +externaldns:source:fqdn-template=false +// +externaldns:source:fqdn-template=true // +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-tcproute @@ -112,7 +112,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:resources=TCPRoute.gateway.networking.k8s.io // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single -// +externaldns:source:fqdn-template=false +// +externaldns:source:fqdn-template=true // +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-tlsroute @@ -121,7 +121,7 @@ func newGatewayInformerFactory(client gateway.Interface, namespace string, label // +externaldns:source:resources=TLSRoute.gateway.networking.k8s.io // +externaldns:source:filters=annotation,label // +externaldns:source:namespace=all,single -// +externaldns:source:fqdn-template=false +// +externaldns:source:fqdn-template=true // +externaldns:source:provider-specific=true // // +externaldns:source:name=gateway-udproute