Compare commits

..

4 commits

Author SHA1 Message Date
a3c1875eaa
Merge branch 'master' of github.com:traefik/traefik
All checks were successful
Build & Push / build-and-push (push) Successful in 21m43s
2024-11-10 22:41:40 +05:30
IIpragmaII
ec00c4aa42
Configurable path for sticky cookies 2024-11-06 16:04:04 +01:00
Bmagic
552bd8f180
Add AbortOnPluginFailure option to abort startup on plugin load failure 2024-11-06 11:58:04 +01:00
Shreyas Kirtane
97caf758ef
Make the IngressRoute kind optional 2024-11-04 16:26:04 +01:00
36 changed files with 579 additions and 38 deletions

View file

@ -238,6 +238,9 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
} }
pluginBuilder, err := createPluginBuilder(staticConfiguration) pluginBuilder, err := createPluginBuilder(staticConfiguration)
if err != nil && staticConfiguration.Experimental != nil && staticConfiguration.Experimental.AbortOnPluginFailure {
return nil, fmt.Errorf("plugin: failed to create plugin builder: %w", err)
}
if err != nil { if err != nil {
pluginLogger.Err(err).Msg("Plugins are disabled because an error has occurred.") pluginLogger.Err(err).Msg("Plugins are disabled because an error has occurred.")
} else if hasPlugins { } else if hasPlugins {

View file

@ -191,6 +191,7 @@
- "traefik.http.services.service02.loadbalancer.sticky.cookie.httponly=true" - "traefik.http.services.service02.loadbalancer.sticky.cookie.httponly=true"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.maxage=42" - "traefik.http.services.service02.loadbalancer.sticky.cookie.maxage=42"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.name=foobar" - "traefik.http.services.service02.loadbalancer.sticky.cookie.name=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.path=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar" - "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true" - "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service02.loadbalancer.server.port=foobar" - "traefik.http.services.service02.loadbalancer.server.port=foobar"

View file

@ -55,6 +55,7 @@
httpOnly = true httpOnly = true
sameSite = "foobar" sameSite = "foobar"
maxAge = 42 maxAge = 42
path = "foobar"
[[http.services.Service02.loadBalancer.servers]] [[http.services.Service02.loadBalancer.servers]]
url = "foobar" url = "foobar"
@ -112,6 +113,7 @@
httpOnly = true httpOnly = true
sameSite = "foobar" sameSite = "foobar"
maxAge = 42 maxAge = 42
path = "foobar"
[http.services.Service04.weighted.healthCheck] [http.services.Service04.weighted.healthCheck]
[http.middlewares] [http.middlewares]
[http.middlewares.Middleware01] [http.middlewares.Middleware01]

View file

@ -63,6 +63,7 @@ http:
httpOnly: true httpOnly: true
sameSite: foobar sameSite: foobar
maxAge: 42 maxAge: 42
path: foobar
servers: servers:
- url: foobar - url: foobar
weight: 42 weight: 42
@ -113,6 +114,7 @@ http:
httpOnly: true httpOnly: true
sameSite: foobar sameSite: foobar
maxAge: 42 maxAge: 42
path: foobar
healthCheck: {} healthCheck: {}
middlewares: middlewares:
Middleware01: Middleware01:

View file

@ -57,6 +57,7 @@ spec:
description: |- description: |-
Kind defines the kind of the route. Kind defines the kind of the route.
Rule is the only supported kind. Rule is the only supported kind.
If not defined, defaults to Rule.
enum: enum:
- Rule - Rule
type: string type: string
@ -241,13 +242,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string type: string
required: required:
- kind
- match - match
type: object type: object
type: array type: array
@ -1133,13 +1139,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2686,13 +2698,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2793,13 +2811,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2976,13 +3000,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -3023,13 +3053,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.

View file

@ -266,6 +266,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` | | `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` | | `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/name` | `foobar` | | `traefik/http/services/Service02/loadBalancer/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/path` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/sameSite` | `foobar` | | `traefik/http/services/Service02/loadBalancer/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` | | `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` |
| `traefik/http/services/Service03/mirroring/healthCheck` | `` | | `traefik/http/services/Service03/mirroring/healthCheck` | `` |
@ -284,6 +285,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/services/Service04/weighted/sticky/cookie/httpOnly` | `true` | | `traefik/http/services/Service04/weighted/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service04/weighted/sticky/cookie/maxAge` | `42` | | `traefik/http/services/Service04/weighted/sticky/cookie/maxAge` | `42` |
| `traefik/http/services/Service04/weighted/sticky/cookie/name` | `foobar` | | `traefik/http/services/Service04/weighted/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/path` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/sameSite` | `foobar` | | `traefik/http/services/Service04/weighted/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/secure` | `true` | | `traefik/http/services/Service04/weighted/sticky/cookie/secure` | `true` |
| `traefik/tcp/middlewares/TCPMiddleware01/ipAllowList/sourceRange/0` | `foobar` | | `traefik/tcp/middlewares/TCPMiddleware01/ipAllowList/sourceRange/0` | `foobar` |

View file

@ -57,6 +57,7 @@ spec:
description: |- description: |-
Kind defines the kind of the route. Kind defines the kind of the route.
Rule is the only supported kind. Rule is the only supported kind.
If not defined, defaults to Rule.
enum: enum:
- Rule - Rule
type: string type: string
@ -241,13 +242,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string type: string
required: required:
- kind
- match - match
type: object type: object
type: array type: array

View file

@ -409,13 +409,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.

View file

@ -279,13 +279,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -386,13 +392,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -569,13 +581,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -616,13 +634,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.

View file

@ -228,6 +228,9 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
`--entrypoints.<name>.udp.timeout`: `--entrypoints.<name>.udp.timeout`:
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```) Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
`--experimental.abortonpluginfailure`:
Defines whether all plugins must be loaded successfully for Traefik to start. (Default: ```false```)
`--experimental.fastproxy`: `--experimental.fastproxy`:
Enable the FastProxy implementation. (Default: ```false```) Enable the FastProxy implementation. (Default: ```false```)

View file

@ -228,6 +228,9 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
`TRAEFIK_ENTRYPOINTS_<NAME>_UDP_TIMEOUT`: `TRAEFIK_ENTRYPOINTS_<NAME>_UDP_TIMEOUT`:
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```) Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
`TRAEFIK_EXPERIMENTAL_ABORTONPLUGINFAILURE`:
Defines whether all plugins must be loaded successfully for Traefik to start. (Default: ```false```)
`TRAEFIK_EXPERIMENTAL_FASTPROXY`: `TRAEFIK_EXPERIMENTAL_FASTPROXY`:
Enable the FastProxy implementation. (Default: ```false```) Enable the FastProxy implementation. (Default: ```false```)

View file

@ -488,6 +488,7 @@
[certificatesResolvers.CertificateResolver1.tailscale] [certificatesResolvers.CertificateResolver1.tailscale]
[experimental] [experimental]
abortOnPluginFailure = true
kubernetesGateway = true kubernetesGateway = true
[experimental.plugins] [experimental.plugins]
[experimental.plugins.Descriptor0] [experimental.plugins.Descriptor0]

View file

@ -576,6 +576,7 @@ experimental:
mounts: mounts:
- foobar - foobar
- foobar - foobar
abortOnPluginFailure: true
fastProxy: fastProxy:
debug: true debug: true
kubernetesGateway: true kubernetesGateway: true

View file

@ -265,6 +265,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`" ??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information. See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -380,6 +380,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar" - "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`" ??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information. See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -267,6 +267,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`" ??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information. See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -352,6 +352,7 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
secure: true secure: true
sameSite: none sameSite: none
maxAge: 42 maxAge: 42
path: /foo
strategy: RoundRobin strategy: RoundRobin
weight: 10 weight: 10
nativeLB: true # [12] nativeLB: true # [12]
@ -377,11 +378,11 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
| [4] | `routes[n].priority` | Defines the [priority](../routers/index.md#priority) to disambiguate rules of the same length, for route matching | | [4] | `routes[n].priority` | Defines the [priority](../routers/index.md#priority) to disambiguate rules of the same length, for route matching |
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) | | [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name | | [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace. It can be omitted when the Middleware is in the IngressRoute namespace. | | [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace. It can be omitted when the Middleware is in the IngressRoute namespace. |
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) | | [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) |
| [9] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. | | [9] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. |
| [10] | `services[n].serversTransport` | Defines the reference to a [ServersTransport](#kind-serverstransport). The ServersTransport namespace is assumed to be the [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) namespace (see [ServersTransport reference](#serverstransport-reference)). | | [10] | `services[n].serversTransport` | Defines the reference to a [ServersTransport](#kind-serverstransport). The ServersTransport namespace is assumed to be the [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) namespace (see [ServersTransport reference](#serverstransport-reference)). |
| [11] | `services[n].healthCheck` | Defines the HealthCheck when service references a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName. | | [11] | `services[n].healthCheck` | Defines the HealthCheck when service references a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName. |
| [12] | `services[n].nativeLB` | Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. | | [12] | `services[n].nativeLB` | Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. |
| [13] | `services[n].nodePortLB` | Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. | | [13] | `services[n].nodePortLB` | Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. |
| [14] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration | | [14] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |

View file

@ -383,6 +383,14 @@ which in turn will create the resulting routers, services, handlers, etc.
traefik.ingress.kubernetes.io/service.sticky.cookie.maxage: 42 traefik.ingress.kubernetes.io/service.sticky.cookie.maxage: 42
``` ```
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.ingress.kubernetes.io/service.sticky.cookie.path: /foobar
```
## Path Types on Kubernetes 1.18+ ## Path Types on Kubernetes 1.18+
If the Kubernetes cluster version is 1.18+, If the Kubernetes cluster version is 1.18+,

View file

@ -228,6 +228,14 @@ A Story of key & values
|-------------------------------------------------------------------|----------| |-------------------------------------------------------------------|----------|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/name` | `foobar` | | `traefik/http/services/myservice/loadbalancer/sticky/cookie/name` | `foobar` |
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
| Key (Path) | Value |
|-------------------------------------------------------------------|-----------|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/path` | `/foobar` |
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/secure`" ??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information. See [sticky sessions](../services/index.md#sticky-sessions) for more information.
@ -320,6 +328,12 @@ A Story of key & values
|----------------------------------------------------------------------|-------| |----------------------------------------------------------------------|-------|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/maxage` | `42` | | `traefik/http/services/<service_name>/weighted/sticky/cookie/maxage` | `42` |
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/path`"
| Key (Path) | Value |
|----------------------------------------------------------------------|-----------|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/path` | `/foobar` |
### Middleware ### Middleware
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md). More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).

View file

@ -281,6 +281,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42 traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`" ??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
See [response forwarding](../services/index.md#response-forwarding) for more information. See [response forwarding](../services/index.md#response-forwarding) for more information.

View file

@ -394,6 +394,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar" - "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`" ??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information. See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -57,6 +57,7 @@ spec:
description: |- description: |-
Kind defines the kind of the route. Kind defines the kind of the route.
Rule is the only supported kind. Rule is the only supported kind.
If not defined, defaults to Rule.
enum: enum:
- Rule - Rule
type: string type: string
@ -241,13 +242,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string type: string
required: required:
- kind
- match - match
type: object type: object
type: array type: array
@ -1133,13 +1139,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2686,13 +2698,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2793,13 +2811,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -2976,13 +3000,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.
@ -3023,13 +3053,19 @@ spec:
type: boolean type: boolean
maxAge: maxAge:
description: |- description: |-
MaxAge indicates the number of seconds until the cookie expires. MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately. When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires. When set to zero, the cookie never expires.
type: integer type: integer
name: name:
description: Name defines the Cookie name. description: Name defines the Cookie name.
type: string type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite: sameSite:
description: |- description: |-
SameSite defines the same site policy. SameSite defines the same site policy.

View file

@ -175,10 +175,20 @@ type Cookie struct {
// SameSite defines the same site policy. // SameSite defines the same site policy.
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite // More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"` SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
// MaxAge indicates the number of seconds until the cookie expires. // MaxAge defines the number of seconds until the cookie expires.
// When set to a negative number, the cookie expires immediately. // When set to a negative number, the cookie expires immediately.
// When set to zero, the cookie never expires. // When set to zero, the cookie never expires.
MaxAge int `json:"maxAge,omitempty" toml:"maxAge,omitempty" yaml:"maxAge,omitempty" export:"true"` MaxAge int `json:"maxAge,omitempty" toml:"maxAge,omitempty" yaml:"maxAge,omitempty" export:"true"`
// Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
// When not provided the cookie will be sent on every request to the domain.
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
Path *string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
}
// SetDefaults set the default values for a Cookie.
func (c *Cookie) SetDefaults() {
defaultPath := "/"
c.Path = &defaultPath
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View file

@ -266,6 +266,11 @@ func (in *ContentType) DeepCopy() *ContentType {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Cookie) DeepCopyInto(out *Cookie) { func (in *Cookie) DeepCopyInto(out *Cookie) {
*out = *in *out = *in
if in.Path != nil {
in, out := &in.Path, &out.Path
*out = new(string)
**out = **in
}
return return
} }
@ -1517,7 +1522,7 @@ func (in *Sticky) DeepCopyInto(out *Sticky) {
if in.Cookie != nil { if in.Cookie != nil {
in, out := &in.Cookie, &out.Cookie in, out := &in.Cookie, &out.Cookie
*out = new(Cookie) *out = new(Cookie)
**out = **in (*in).DeepCopyInto(*out)
} }
return return
} }

View file

@ -174,6 +174,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service0.loadbalancer.server.port": "8080", "traefik.http.services.Service0.loadbalancer.server.port": "8080",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar", "traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.secure": "true", "traefik.http.services.Service0.loadbalancer.sticky.cookie.secure": "true",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.path": "/foobar",
"traefik.http.services.Service0.loadbalancer.serversTransport": "foobar", "traefik.http.services.Service0.loadbalancer.serversTransport": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name0": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.headers.name0": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name1": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.headers.name1": "foobar",
@ -674,6 +675,7 @@ func TestDecodeConfiguration(t *testing.T) {
Name: "foobar", Name: "foobar",
Secure: true, Secure: true,
HTTPOnly: false, HTTPOnly: false,
Path: func(v string) *string { return &v }("/foobar"),
}, },
}, },
Servers: []dynamic.Server{ Servers: []dynamic.Server{
@ -1196,6 +1198,7 @@ func TestEncodeConfiguration(t *testing.T) {
Cookie: &dynamic.Cookie{ Cookie: &dynamic.Cookie{
Name: "foobar", Name: "foobar",
HTTPOnly: true, HTTPOnly: true,
Path: func(v string) *string { return &v }("/foobar"),
}, },
}, },
Servers: []dynamic.Server{ Servers: []dynamic.Server{
@ -1433,6 +1436,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true", "traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false", "traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.MaxAge": "0", "traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.MaxAge": "0",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Path": "/foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.ServersTransport": "foobar", "traefik.HTTP.Services.Service0.LoadBalancer.ServersTransport": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",

View file

@ -4,8 +4,9 @@ import "github.com/traefik/traefik/v3/pkg/plugins"
// Experimental experimental Traefik features. // Experimental experimental Traefik features.
type Experimental struct { type Experimental struct {
Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"` Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"`
LocalPlugins map[string]plugins.LocalDescriptor `description:"Local plugins configuration." json:"localPlugins,omitempty" toml:"localPlugins,omitempty" yaml:"localPlugins,omitempty" export:"true"` LocalPlugins map[string]plugins.LocalDescriptor `description:"Local plugins configuration." json:"localPlugins,omitempty" toml:"localPlugins,omitempty" yaml:"localPlugins,omitempty" export:"true"`
AbortOnPluginFailure bool `description:"Defines whether all plugins must be loaded successfully for Traefik to start." json:"abortOnPluginFailure,omitempty" toml:"abortOnPluginFailure,omitempty" yaml:"abortOnPluginFailure,omitempty" export:"true"`
FastProxy *FastProxyConfig `description:"Enable the FastProxy implementation." json:"fastProxy,omitempty" toml:"fastProxy,omitempty" yaml:"fastProxy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` FastProxy *FastProxyConfig `description:"Enable the FastProxy implementation." json:"fastProxy,omitempty" toml:"fastProxy,omitempty" yaml:"fastProxy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`

View file

@ -0,0 +1,81 @@
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: sticky-default
namespace: default
spec:
weighted:
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
services:
- name: whoami3
port: 8443
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: sticky
namespace: default
spec:
weighted:
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
path: /foo
services:
- name: whoami3
port: 8443
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test2.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`traefik-service`)
kind: Rule
services:
- name: sticky
kind: TraefikService
- name: sticky-default
kind: TraefikService
- match: Host(`k8s-service`)
kind: Rule
services:
- name: whoami
port: 80
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
path: /foo
- name: whoami2
port: 8080
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42

View file

@ -60,7 +60,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
} }
for _, route := range ingressRoute.Spec.Routes { for _, route := range ingressRoute.Spec.Routes {
if route.Kind != "Rule" { if len(route.Kind) > 0 && route.Kind != "Rule" {
logger.Error().Msgf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind) logger.Error().Msgf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
continue continue
} }
@ -248,10 +248,28 @@ func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tS
}) })
} }
var sticky *dynamic.Sticky
if tService.Weighted.Sticky != nil && tService.Weighted.Sticky.Cookie != nil {
sticky = &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: tService.Weighted.Sticky.Cookie.Name,
Secure: tService.Weighted.Sticky.Cookie.Secure,
HTTPOnly: tService.Weighted.Sticky.Cookie.HTTPOnly,
SameSite: tService.Weighted.Sticky.Cookie.SameSite,
MaxAge: tService.Weighted.Sticky.Cookie.MaxAge,
},
}
sticky.Cookie.SetDefaults()
if tService.Weighted.Sticky.Cookie.Path != nil {
sticky.Cookie.Path = tService.Weighted.Sticky.Cookie.Path
}
}
conf[id] = &dynamic.Service{ conf[id] = &dynamic.Service{
Weighted: &dynamic.WeightedRoundRobin{ Weighted: &dynamic.WeightedRoundRobin{
Services: wrrServices, Services: wrrServices,
Sticky: tService.Weighted.Sticky, Sticky: sticky,
}, },
} }
return nil return nil
@ -353,7 +371,22 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load
} }
} }
lb.Sticky = svc.Sticky if svc.Sticky != nil && svc.Sticky.Cookie != nil {
lb.Sticky = &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: svc.Sticky.Cookie.Name,
Secure: svc.Sticky.Cookie.Secure,
HTTPOnly: svc.Sticky.Cookie.HTTPOnly,
SameSite: svc.Sticky.Cookie.SameSite,
MaxAge: svc.Sticky.Cookie.MaxAge,
},
}
lb.Sticky.Cookie.SetDefaults()
if svc.Sticky.Cookie.Path != nil {
lb.Sticky.Cookie.Path = svc.Sticky.Cookie.Path
}
}
lb.ServersTransport, err = c.makeServersTransportKey(namespace, svc.ServersTransport) lb.ServersTransport, err = c.makeServersTransportKey(namespace, svc.ServersTransport)
if err != nil { if err != nil {

View file

@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
kubefake "k8s.io/client-go/kubernetes/fake" kubefake "k8s.io/client-go/kubernetes/fake"
kscheme "k8s.io/client-go/kubernetes/scheme" kscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/pointer"
) )
var _ provider.Provider = (*Provider)(nil) var _ provider.Provider = (*Provider)(nil)
@ -3114,8 +3115,8 @@ func TestLoadIngressRoutes(t *testing.T) {
}, },
}, },
{ {
desc: "Route with kind not of a rule type (empty kind) is ignored", desc: "Route with empty kind is allowed",
paths: []string{"services.yml", "with_wrong_rule_kind.yml"}, paths: []string{"services.yml", "with_empty_rule_kind.yml"},
expected: &dynamic.Configuration{ expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{ UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{}, Routers: map[string]*dynamic.UDPRouter{},
@ -3129,9 +3130,33 @@ func TestLoadIngressRoutes(t *testing.T) {
ServersTransports: map[string]*dynamic.TCPServersTransport{}, ServersTransports: map[string]*dynamic.TCPServersTransport{},
}, },
HTTP: &dynamic.HTTPConfiguration{ HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{}, Routers: map[string]*dynamic.Router{
Middlewares: map[string]*dynamic.Middleware{}, "default-test-route-02719a68b11e915a4b23": {
Services: map[string]*dynamic.Service{}, EntryPoints: []string{"web"},
Service: "default-test-route-02719a68b11e915a4b23",
Rule: "/prefix",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-02719a68b11e915a4b23": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{}, ServersTransports: map[string]*dynamic.ServersTransport{},
}, },
}, },
@ -4879,6 +4904,178 @@ func TestLoadIngressRoutes(t *testing.T) {
TLS: &dynamic.TLSConfiguration{}, TLS: &dynamic.TLSConfiguration{},
}, },
}, },
{
desc: "Simple Ingress Route with sticky",
allowCrossNamespace: true,
paths: []string{"services.yml", "with_sticky.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
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-test2-route-840425136fbd5d85a4ad": {
EntryPoints: []string{"web"},
Service: "default-test2-route-840425136fbd5d85a4ad",
Rule: "Host(`k8s-service`)",
},
"default-test2-route-4f06607bbc69f34a4db5": {
EntryPoints: []string{"web"},
Service: "default-test2-route-4f06607bbc69f34a4db5",
Rule: "Host(`traefik-service`)",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test2-route-840425136fbd5d85a4ad": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: Int(1),
},
{
Name: "default-whoami2-8080",
Weight: Int(1),
},
},
},
},
"default-test2-route-4f06607bbc69f34a4db5": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-sticky",
Weight: Int(1),
},
{
Name: "default-sticky-default",
Weight: Int(1),
},
},
},
},
"default-sticky": {
Weighted: &dynamic.WeightedRoundRobin{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/foo"),
},
},
Services: []dynamic.WRRService{
{
Name: "default-whoami3-8443",
Weight: Int(1),
},
},
},
},
"default-sticky-default": {
Weighted: &dynamic.WeightedRoundRobin{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/"),
},
},
Services: []dynamic.WRRService{
{
Name: "default-whoami3-8443",
Weight: Int(1),
},
},
},
},
"default-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/"),
},
},
Servers: []dynamic.Server{
{
URL: "http://10.10.0.3:8080",
},
{
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/foo"),
},
},
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami3-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.7:8443",
},
{
URL: "http://10.10.0.8:8443",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
} }
for _, test := range testCases { for _, test := range testCases {

View file

@ -28,8 +28,9 @@ type Route struct {
Match string `json:"match"` Match string `json:"match"`
// Kind defines the kind of the route. // Kind defines the kind of the route.
// Rule is the only supported kind. // Rule is the only supported kind.
// If not defined, defaults to Rule.
// +kubebuilder:validation:Enum=Rule // +kubebuilder:validation:Enum=Rule
Kind string `json:"kind"` Kind string `json:"kind,omitempty"`
// Priority defines the router's priority. // Priority defines the router's priority.
// More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#priority // More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#priority
Priority int `json:"priority,omitempty"` Priority int `json:"priority,omitempty"`

View file

@ -113,6 +113,7 @@ func Test_parseServiceConfig(t *testing.T) {
"traefik.ingress.kubernetes.io/service.sticky.cookie.name": "foobar", "traefik.ingress.kubernetes.io/service.sticky.cookie.name": "foobar",
"traefik.ingress.kubernetes.io/service.sticky.cookie.secure": "true", "traefik.ingress.kubernetes.io/service.sticky.cookie.secure": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.samesite": "none", "traefik.ingress.kubernetes.io/service.sticky.cookie.samesite": "none",
"traefik.ingress.kubernetes.io/service.sticky.cookie.path": "foobar",
}, },
expected: &ServiceConfig{ expected: &ServiceConfig{
Service: &ServiceIng{ Service: &ServiceIng{
@ -122,6 +123,7 @@ func Test_parseServiceConfig(t *testing.T) {
Secure: true, Secure: true,
HTTPOnly: true, HTTPOnly: true,
SameSite: "none", SameSite: "none",
Path: String("foobar"),
}, },
}, },
ServersScheme: "protocol", ServersScheme: "protocol",
@ -138,7 +140,11 @@ func Test_parseServiceConfig(t *testing.T) {
}, },
expected: &ServiceConfig{ expected: &ServiceConfig{
Service: &ServiceIng{ Service: &ServiceIng{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}}, Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Path: String("/"),
},
},
PassHostHeader: Bool(true), PassHostHeader: Bool(true),
}, },
}, },

View file

@ -24,6 +24,8 @@ var _ provider.Provider = (*Provider)(nil)
func Bool(v bool) *bool { return &v } func Bool(v bool) *bool { return &v }
func String(v string) *string { return &v }
func TestLoadConfigurationFromIngresses(t *testing.T) { func TestLoadConfigurationFromIngresses(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
@ -126,6 +128,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Name: "foobar", Name: "foobar",
Secure: true, Secure: true,
HTTPOnly: true, HTTPOnly: true,
Path: String("/"),
}, },
}, },
Servers: []dynamic.Server{ Servers: []dynamic.Server{

View file

@ -58,6 +58,7 @@ func Test_buildConfiguration(t *testing.T) {
"traefik/http/services/Service01/loadBalancer/sticky/cookie/name": "foobar", "traefik/http/services/Service01/loadBalancer/sticky/cookie/name": "foobar",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/secure": "true", "traefik/http/services/Service01/loadBalancer/sticky/cookie/secure": "true",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/httpOnly": "true", "traefik/http/services/Service01/loadBalancer/sticky/cookie/httpOnly": "true",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/path": "foobar",
"traefik/http/services/Service01/loadBalancer/servers/0/url": "foobar", "traefik/http/services/Service01/loadBalancer/servers/0/url": "foobar",
"traefik/http/services/Service01/loadBalancer/servers/1/url": "foobar", "traefik/http/services/Service01/loadBalancer/servers/1/url": "foobar",
"traefik/http/services/Service02/mirroring/service": "foobar", "traefik/http/services/Service02/mirroring/service": "foobar",
@ -70,6 +71,7 @@ func Test_buildConfiguration(t *testing.T) {
"traefik/http/services/Service03/weighted/sticky/cookie/name": "foobar", "traefik/http/services/Service03/weighted/sticky/cookie/name": "foobar",
"traefik/http/services/Service03/weighted/sticky/cookie/secure": "true", "traefik/http/services/Service03/weighted/sticky/cookie/secure": "true",
"traefik/http/services/Service03/weighted/sticky/cookie/httpOnly": "true", "traefik/http/services/Service03/weighted/sticky/cookie/httpOnly": "true",
"traefik/http/services/Service03/weighted/sticky/cookie/path": "foobar",
"traefik/http/services/Service03/weighted/services/0/name": "foobar", "traefik/http/services/Service03/weighted/services/0/name": "foobar",
"traefik/http/services/Service03/weighted/services/0/weight": "42", "traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "foobar", "traefik/http/services/Service03/weighted/services/1/name": "foobar",
@ -642,6 +644,7 @@ func Test_buildConfiguration(t *testing.T) {
Name: "foobar", Name: "foobar",
Secure: true, Secure: true,
HTTPOnly: true, HTTPOnly: true,
Path: func(v string) *string { return &v }("foobar"),
}, },
}, },
Servers: []dynamic.Server{ Servers: []dynamic.Server{
@ -708,6 +711,7 @@ func Test_buildConfiguration(t *testing.T) {
Name: "foobar", Name: "foobar",
Secure: true, Secure: true,
HTTPOnly: true, HTTPOnly: true,
Path: func(v string) *string { return &v }("foobar"),
}, },
}, },
}, },

View file

@ -26,6 +26,7 @@ type stickyCookie struct {
httpOnly bool httpOnly bool
sameSite string sameSite string
maxAge int maxAge int
path string
} }
func convertSameSite(sameSite string) http.SameSite { func convertSameSite(sameSite string) http.SameSite {
@ -79,6 +80,10 @@ func New(sticky *dynamic.Sticky, wantHealthCheck bool) *Balancer {
httpOnly: sticky.Cookie.HTTPOnly, httpOnly: sticky.Cookie.HTTPOnly,
sameSite: sticky.Cookie.SameSite, sameSite: sticky.Cookie.SameSite,
maxAge: sticky.Cookie.MaxAge, maxAge: sticky.Cookie.MaxAge,
path: "/",
}
if sticky.Cookie.Path != nil {
balancer.stickyCookie.path = *sticky.Cookie.Path
} }
} }
@ -236,7 +241,7 @@ func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
cookie := &http.Cookie{ cookie := &http.Cookie{
Name: b.stickyCookie.name, Name: b.stickyCookie.name,
Value: hash(server.name), Value: hash(server.name),
Path: "/", Path: b.stickyCookie.path,
HttpOnly: b.stickyCookie.httpOnly, HttpOnly: b.stickyCookie.httpOnly,
Secure: b.stickyCookie.secure, Secure: b.stickyCookie.secure,
SameSite: convertSameSite(b.stickyCookie.sameSite), SameSite: convertSameSite(b.stickyCookie.sameSite),

View file

@ -226,6 +226,7 @@ func TestSticky(t *testing.T) {
HTTPOnly: true, HTTPOnly: true,
SameSite: "none", SameSite: "none",
MaxAge: 42, MaxAge: 42,
Path: func(v string) *string { return &v }("/foo"),
}, },
}, false) }, false)
@ -263,6 +264,7 @@ func TestSticky(t *testing.T) {
assert.True(t, recorder.cookies["test"].Secure) assert.True(t, recorder.cookies["test"].Secure)
assert.Equal(t, http.SameSiteNoneMode, recorder.cookies["test"].SameSite) assert.Equal(t, http.SameSiteNoneMode, recorder.cookies["test"].SameSite)
assert.Equal(t, 42, recorder.cookies["test"].MaxAge) assert.Equal(t, 42, recorder.cookies["test"].MaxAge)
assert.Equal(t, "/foo", recorder.cookies["test"].Path)
} }
func TestSticky_FallBack(t *testing.T) { func TestSticky_FallBack(t *testing.T) {