Add ingressClassName field to the CRDs spec

This commit is contained in:
Krypton
2026-01-14 15:30:05 +01:00
committed by GitHub
parent 5492079915
commit a6516d36eb
28 changed files with 723 additions and 31 deletions
@@ -47,6 +47,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
parentRefs:
description: |-
ParentRefs defines references to parent IngressRoute resources for multi-layer routing.
@@ -509,6 +513,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -765,6 +773,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -48,6 +48,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
parentRefs:
description: |-
ParentRefs defines references to parent IngressRoute resources for multi-layer routing.
@@ -48,6 +48,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -48,6 +48,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -354,7 +354,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-providers-kubernetescrd-certauthfilepath" href="#opt-providers-kubernetescrd-certauthfilepath" title="#opt-providers-kubernetescrd-certauthfilepath">providers.kubernetescrd.certauthfilepath</a> | Kubernetes certificate authority file path (not needed for in-cluster client). | |
| <a id="opt-providers-kubernetescrd-disableclusterscoperesources" href="#opt-providers-kubernetescrd-disableclusterscoperesources" title="#opt-providers-kubernetescrd-disableclusterscoperesources">providers.kubernetescrd.disableclusterscoperesources</a> | Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services). | false |
| <a id="opt-providers-kubernetescrd-endpoint" href="#opt-providers-kubernetescrd-endpoint" title="#opt-providers-kubernetescrd-endpoint">providers.kubernetescrd.endpoint</a> | Kubernetes server endpoint (required for external cluster client). | |
| <a id="opt-providers-kubernetescrd-ingressclass" href="#opt-providers-kubernetescrd-ingressclass" title="#opt-providers-kubernetescrd-ingressclass">providers.kubernetescrd.ingressclass</a> | Value of kubernetes.io/ingress.class annotation to watch for. | |
| <a id="opt-providers-kubernetescrd-ingressclass" href="#opt-providers-kubernetescrd-ingressclass" title="#opt-providers-kubernetescrd-ingressclass">providers.kubernetescrd.ingressclass</a> | Value of ingressClassName field or kubernetes.io/ingress.class annotation to watch for. | |
| <a id="opt-providers-kubernetescrd-labelselector" href="#opt-providers-kubernetescrd-labelselector" title="#opt-providers-kubernetescrd-labelselector">providers.kubernetescrd.labelselector</a> | Kubernetes label selector to use. | |
| <a id="opt-providers-kubernetescrd-namespaces" href="#opt-providers-kubernetescrd-namespaces" title="#opt-providers-kubernetescrd-namespaces">providers.kubernetescrd.namespaces</a> | Kubernetes namespaces. | |
| <a id="opt-providers-kubernetescrd-nativelbbydefault" href="#opt-providers-kubernetescrd-nativelbbydefault" title="#opt-providers-kubernetescrd-nativelbbydefault">providers.kubernetescrd.nativelbbydefault</a> | Defines whether to use Native Kubernetes load-balancing mode by default. | false |
@@ -60,7 +60,7 @@ providers:
| <a id="opt-providers-kubernetesCRD-certAuthFilePath" href="#opt-providers-kubernetesCRD-certAuthFilePath" title="#opt-providers-kubernetesCRD-certAuthFilePath">`providers.kubernetesCRD.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesCRD-namespaces" href="#opt-providers-kubernetesCRD-namespaces" title="#opt-providers-kubernetesCRD-namespaces">`providers.kubernetesCRD.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | [] | No |
| <a id="opt-providers-kubernetesCRD-labelselector" href="#opt-providers-kubernetesCRD-labelselector" title="#opt-providers-kubernetesCRD-labelselector">`providers.kubernetesCRD.labelselector`</a> | Allow filtering on specific resource objects only using label selectors.<br />Only to Traefik [Custom Resources](#list-of-resources) (they all must match the filter).<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
| <a id="opt-providers-kubernetesCRD-ingressClass" href="#opt-providers-kubernetesCRD-ingressClass" title="#opt-providers-kubernetesCRD-ingressClass">`providers.kubernetesCRD.ingressClass`</a> | Value of `kubernetes.io/ingress.class` annotation that identifies resource objects to be processed.<br />If empty, resources missing the annotation, having an empty value, or the value `traefik` are processed. | "" | No |
| <a id="opt-providers-kubernetesCRD-ingressClass" href="#opt-providers-kubernetesCRD-ingressClass" title="#opt-providers-kubernetesCRD-ingressClass">`providers.kubernetesCRD.ingressClass`</a> | Value of `spec.ingressClassName` field (or the deprecated `kubernetes.io/ingress.class` annotation) that identifies resource objects to be processed.<br />If empty, resources missing the field/annotation, having an empty value, or the value `traefik` are processed.<br />The `spec.ingressClassName` field takes precedence over the annotation. | "" | No |
| <a id="opt-providers-kubernetesCRD-throttleDuration" href="#opt-providers-kubernetesCRD-throttleDuration" title="#opt-providers-kubernetesCRD-throttleDuration">`providers.kubernetesCRD.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
| <a id="opt-providers-kubernetesCRD-allowEmptyServices" href="#opt-providers-kubernetesCRD-allowEmptyServices" title="#opt-providers-kubernetesCRD-allowEmptyServices">`providers.kubernetesCRD.allowEmptyServices`</a> | Allows creating a route to reach a service that has no endpoint available.<br />It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a `503` HTTP Status. | false | No |
| <a id="opt-providers-kubernetesCRD-allowCrossNamespace" href="#opt-providers-kubernetesCRD-allowCrossNamespace" title="#opt-providers-kubernetesCRD-allowCrossNamespace">`providers.kubernetesCRD.allowCrossNamespace`</a> | Allows the `IngressRoutes` to reference resources in namespaces other than theirs. | false | No |
@@ -21,6 +21,7 @@ metadata:
namespace: apps
spec:
ingressClassName: traefik-lb
entryPoints:
- web
parentRefs:
@@ -79,6 +80,7 @@ spec:
| Field | Description | Default | Required |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
| <a id="opt-ingressClassName" href="#opt-ingressClassName" title="#opt-ingressClassName">`ingressClassName`</a> | Defines the [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) cluster resource to use. It replaces the deprecated `kubernetes.io/ingress.class` annotation.<br />The spec field takes precedence over the annotation. | | No |
| <a id="opt-entryPoints" href="#opt-entryPoints" title="#opt-entryPoints">`entryPoints`</a> | List of [entry points](../../../../install-configuration/entrypoints.md) names.<br />If not specified, HTTP routers will accept requests from all EntryPoints in the list of default EntryPoints. | | No |
| <a id="opt-parentRefs" href="#opt-parentRefs" title="#opt-parentRefs">`parentRefs`</a> | List of references to parent IngressRoute resources for multi-layer routing. When specified, this IngressRoute's routers become children of the referenced parent IngressRoute's routers. See [Multi-Layer Routing](#multi-layer-routing-with-ingressroutes) section for details. | | No |
| <a id="opt-parentRefsn-name" href="#opt-parentRefsn-name" title="#opt-parentRefsn-name">`parentRefs[n].name`</a> | Name of the referenced parent IngressRoute resource. | | Yes |
@@ -24,6 +24,7 @@ metadata:
namespace: apps
spec:
ingressClassName: traefik-lb
entryPoints:
- footcp
routes:
@@ -58,6 +59,7 @@ spec:
| Field | Description | Default | Required |
|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|-----------------------|
| <a id="opt-ingressClassName" href="#opt-ingressClassName" title="#opt-ingressClassName">`ingressClassName`</a> | Defines the [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) cluster resource to use. It replaces the deprecated `kubernetes.io/ingress.class` annotation.<br />The spec field takes precedence over the annotation. | | No |
| <a id="opt-entryPoints" href="#opt-entryPoints" title="#opt-entryPoints">`entryPoints`</a> | List of entrypoints names. | | No |
| <a id="opt-routes" href="#opt-routes" title="#opt-routes">`routes`</a> | List of routes. | | Yes |
| <a id="opt-routesn-match" href="#opt-routesn-match" title="#opt-routesn-match">`routes[n].match`</a> | Defines the [rule](../../../tcp/routing/rules-and-priority.md#rules) of the underlying router. | | Yes |
@@ -18,6 +18,7 @@ metadata:
name: ingressrouteudpfoo
namespace: apps
spec:
ingressClassName: traefik-lb
entryPoints:
- fooudp # The entry point where Traefik listens for incoming traffic.
routes:
@@ -32,6 +33,7 @@ spec:
| Field | Description | Default | Required |
|------------------------------------|-----------------------------|-------------------------------------------|-----------------------|
| <a id="opt-ingressClassName" href="#opt-ingressClassName" title="#opt-ingressClassName">`ingressClassName`</a> | Defines the [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) cluster resource to use. It replaces the deprecated `kubernetes.io/ingress.class` annotation.<br />The spec field takes precedence over the annotation. | | No |
| <a id="opt-entryPoints" href="#opt-entryPoints" title="#opt-entryPoints">`entryPoints`</a> | List of entrypoints names. | | No |
| <a id="opt-routes" href="#opt-routes" title="#opt-routes">` routes `</a> | List of routes. | | Yes |
| <a id="opt-routesn-services" href="#opt-routesn-services" title="#opt-routesn-services">`routes[n].services`</a> | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions. See [here](#externalname-service) for `ExternalName Service` setup. | | No |
@@ -48,6 +48,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
parentRefs:
description: |-
ParentRefs defines references to parent IngressRoute resources for multi-layer routing.
@@ -510,6 +514,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -766,6 +774,10 @@ spec:
items:
type: string
type: array
ingressClassName:
description: IngressClassName defines the name of the IngressClass
cluster resource.
type: string
routes:
description: Routes defines the list of routes.
items:
@@ -0,0 +1,17 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik-lb
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: whoamitcp
port: 8000
@@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- match: HostSNI(`foo.com`)
services:
- name: whoamitcp
port: 8000
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- match: HostSNI(`foo.com`)
services:
- name: whoamitcp
port: 8000
@@ -0,0 +1,16 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik-lb
spec:
entryPoints:
- foo
routes:
- services:
- name: whoamiudp
port: 8000
@@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- services:
- name: whoamiudp
port: 8000
@@ -0,0 +1,25 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- services:
- name: whoamiudp
port: 8000
@@ -0,0 +1,19 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik-lb
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
@@ -0,0 +1,28 @@
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
spec:
entryPoints:
- foo
ingressClassName: traefik-lb
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
+16 -4
View File
@@ -57,7 +57,7 @@ type Provider struct {
AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"`
AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"`
IngressClass string `description:"Value of ingressClassName field or kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"`
ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
AllowEmptyServices bool `description:"Allow the creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"`
NativeLBByDefault bool `description:"Defines whether to use Native Kubernetes load-balancing mode by default." json:"nativeLBByDefault,omitempty" toml:"nativeLBByDefault,omitempty" yaml:"nativeLBByDefault,omitempty" export:"true"`
@@ -1447,9 +1447,21 @@ func makeID(namespace, name string) string {
return namespace + "-" + name
}
func shouldProcessIngress(ingressClass, ingressClassAnnotation string) bool {
return ingressClass == ingressClassAnnotation ||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
func shouldProcessIngress(ingressClass, ingressClassName string) bool {
return ingressClass == ingressClassName ||
(len(ingressClass) == 0 && ingressClassName == traefikDefaultIngressClass)
}
// getIngressClassName returns the ingress class name from the spec field or falls back to the
// deprecated annotation. Returns the class name and whether the deprecated annotation was used.
func getIngressClassName(specIngressClassName *string, annotations map[string]string) (string, bool) {
if specIngressClassName != nil {
return *specIngressClassName, false
}
if annotation, ok := annotations[annotationKubernetesIngressClass]; ok && annotation != "" {
return annotation, true
}
return "", false
}
func getTLS(k8sClient Client, secretName, namespace string) (*tls.CertAndStores, error) {
@@ -37,8 +37,11 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
for _, ingressRoute := range client.GetIngressRoutes() {
logger := log.Ctx(ctx).With().Str("ingress", ingressRoute.Name).Str("namespace", ingressRoute.Namespace).Logger()
// TODO keep the name ingressClass?
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
ingressClassName, usingDeprecatedAnnotation := getIngressClassName(ingressRoute.Spec.IngressClassName, ingressRoute.Annotations)
if usingDeprecatedAnnotation {
logger.Warn().Msgf("'%s' is a deprecated annotation, please use spec.ingressClassName instead.", annotationKubernetesIngressClass)
}
if !shouldProcessIngress(p.IngressClass, ingressClassName) {
continue
}
@@ -28,7 +28,11 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
logger := log.Ctx(ctx).With().Str("ingress", ingressRouteTCP.Name).Str("namespace", ingressRouteTCP.Namespace).Logger()
if !shouldProcessIngress(p.IngressClass, ingressRouteTCP.Annotations[annotationKubernetesIngressClass]) {
ingressClassName, usingDeprecatedAnnotation := getIngressClassName(ingressRouteTCP.Spec.IngressClassName, ingressRouteTCP.Annotations)
if usingDeprecatedAnnotation {
logger.Warn().Msgf("'%s' is a deprecated annotation, please use spec.ingressClassName instead.", annotationKubernetesIngressClass)
}
if !shouldProcessIngress(p.IngressClass, ingressClassName) {
continue
}
@@ -1300,6 +1300,135 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TCP Ingress Route, with ingressClassName",
paths: []string{"tcp/services.yml", "tcp/with_ingressclassname.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Simple TCP Ingress Route, with ingressClassName and deprecated annotation",
paths: []string{"tcp/services.yml", "tcp/with_ingressclassname_and_deprecated_annotation.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Simple TCP Ingress Route, with deprecated annotation only",
paths: []string{"tcp/services.yml", "tcp/with_deprecated_annotation_only.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
TLS: &dynamic.TLSConfiguration{},
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Ingress Route with IPv6 backends",
paths: []string{
@@ -4131,6 +4260,153 @@ func TestLoadIngressRoutes(t *testing.T) {
},
},
},
{
desc: "Simple Ingress Route, with ingressClassName",
paths: []string{"services.yml", "with_ingressclassname.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TLS: &dynamic.TLSConfiguration{},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Strategy: dynamic.BalancerStrategyWRR,
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Simple Ingress Route, with ingressClassName and deprecated annotation",
paths: []string{"services.yml", "with_ingressclassname_and_deprecated_annotation.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TLS: &dynamic.TLSConfiguration{},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Strategy: dynamic.BalancerStrategyWRR,
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Simple Ingress Route, with deprecated annotation only",
paths: []string{"services.yml", "with_deprecated_annotation_only.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TLS: &dynamic.TLSConfiguration{},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Strategy: dynamic.BalancerStrategyWRR,
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
},
{
desc: "Simple Ingress Route, with basic auth middleware",
paths: []string{"services.yml", "with_auth.yml"},
@@ -5911,6 +6187,132 @@ func TestLoadIngressRouteUDPs(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple UDP Ingress Route, with ingressClassName",
paths: []string{"udp/services.yml", "udp/with_ingressclassname.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{
"default-test.route-0": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple UDP Ingress Route, with ingressClassName and deprecated annotation",
paths: []string{"udp/services.yml", "udp/with_ingressclassname_and_deprecated_annotation.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{
"default-test.route-0": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple UDP Ingress Route, with deprecated annotation only",
paths: []string{"udp/services.yml", "udp/with_deprecated_annotation_only.yml"},
ingressClass: "traefik-lb",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{
"default-test.route-0": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "10.10.0.1:8000",
},
{
Address: "10.10.0.2:8000",
},
},
},
},
},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "One ingress Route with two different routes",
paths: []string{"udp/services.yml", "udp/with_two_routes.yml"},
@@ -22,7 +22,11 @@ func (p *Provider) loadIngressRouteUDPConfiguration(ctx context.Context, client
for _, ingressRouteUDP := range client.GetIngressRouteUDPs() {
logger := log.Ctx(ctx).With().Str("ingress", ingressRouteUDP.Name).Str("namespace", ingressRouteUDP.Namespace).Logger()
if !shouldProcessIngress(p.IngressClass, ingressRouteUDP.Annotations[annotationKubernetesIngressClass]) {
ingressClassName, usingDeprecatedAnnotation := getIngressClassName(ingressRouteUDP.Spec.IngressClassName, ingressRouteUDP.Annotations)
if usingDeprecatedAnnotation {
logger.Warn().Msgf("'%s' is a deprecated annotation, please use spec.ingressClassName instead.", annotationKubernetesIngressClass)
}
if !shouldProcessIngress(p.IngressClass, ingressClassName) {
continue
}
@@ -9,13 +9,15 @@ import (
// IngressRouteSpec defines the desired state of IngressRoute.
type IngressRouteSpec struct {
// Routes defines the list of routes.
Routes []Route `json:"routes"`
// IngressClassName defines the name of the IngressClass cluster resource.
IngressClassName *string `json:"ingressClassName,omitempty"`
// EntryPoints defines the list of entry point names to bind to.
// Entry points have to be configured in the static configuration.
// More info: https://doc.traefik.io/traefik/v3.6/reference/install-configuration/entrypoints/
// Default: all.
EntryPoints []string `json:"entryPoints,omitempty"`
// Routes defines the list of routes.
Routes []Route `json:"routes"`
// TLS defines the TLS configuration.
// More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/router/#tls
TLS *TLS `json:"tls,omitempty"`
@@ -9,13 +9,15 @@ import (
// IngressRouteTCPSpec defines the desired state of IngressRouteTCP.
type IngressRouteTCPSpec struct {
// Routes defines the list of routes.
Routes []RouteTCP `json:"routes"`
// IngressClassName defines the name of the IngressClass cluster resource.
IngressClassName *string `json:"ingressClassName,omitempty"`
// EntryPoints defines the list of entry point names to bind to.
// Entry points have to be configured in the static configuration.
// More info: https://doc.traefik.io/traefik/v3.6/reference/install-configuration/entrypoints/
// Default: all.
EntryPoints []string `json:"entryPoints,omitempty"`
// Routes defines the list of routes.
Routes []RouteTCP `json:"routes"`
// TLS defines the TLS configuration on a layer 4 / TCP Route.
// More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/router/#tls
TLS *TLSTCP `json:"tls,omitempty"`
@@ -7,13 +7,15 @@ import (
// IngressRouteUDPSpec defines the desired state of a IngressRouteUDP.
type IngressRouteUDPSpec struct {
// Routes defines the list of routes.
Routes []RouteUDP `json:"routes"`
// IngressClassName defines the name of the IngressClass cluster resource.
IngressClassName *string `json:"ingressClassName,omitempty"`
// EntryPoints defines the list of entry point names to bind to.
// Entry points have to be configured in the static configuration.
// More info: https://doc.traefik.io/traefik/v3.6/reference/install-configuration/entrypoints/
// Default: all.
EntryPoints []string `json:"entryPoints,omitempty"`
// Routes defines the list of routes.
Routes []RouteUDP `json:"routes"`
}
// RouteUDP holds the UDP route configuration.
@@ -451,6 +451,16 @@ func (in *IngressRouteRef) DeepCopy() *IngressRouteRef {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressRouteSpec) DeepCopyInto(out *IngressRouteSpec) {
*out = *in
if in.IngressClassName != nil {
in, out := &in.IngressClassName, &out.IngressClassName
*out = new(string)
**out = **in
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Routes != nil {
in, out := &in.Routes, &out.Routes
*out = make([]Route, len(*in))
@@ -458,11 +468,6 @@ func (in *IngressRouteSpec) DeepCopyInto(out *IngressRouteSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(TLS)
@@ -549,6 +554,16 @@ func (in *IngressRouteTCPList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressRouteTCPSpec) DeepCopyInto(out *IngressRouteTCPSpec) {
*out = *in
if in.IngressClassName != nil {
in, out := &in.IngressClassName, &out.IngressClassName
*out = new(string)
**out = **in
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Routes != nil {
in, out := &in.Routes, &out.Routes
*out = make([]RouteTCP, len(*in))
@@ -556,11 +571,6 @@ func (in *IngressRouteTCPSpec) DeepCopyInto(out *IngressRouteTCPSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(TLSTCP)
@@ -642,6 +652,16 @@ func (in *IngressRouteUDPList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressRouteUDPSpec) DeepCopyInto(out *IngressRouteUDPSpec) {
*out = *in
if in.IngressClassName != nil {
in, out := &in.IngressClassName, &out.IngressClassName
*out = new(string)
**out = **in
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Routes != nil {
in, out := &in.Routes, &out.Routes
*out = make([]RouteUDP, len(*in))
@@ -649,11 +669,6 @@ func (in *IngressRouteUDPSpec) DeepCopyInto(out *IngressRouteUDPSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.EntryPoints != nil {
in, out := &in.EntryPoints, &out.EntryPoints
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}