mirror of
https://github.com/traefik/traefik
synced 2026-02-03 07:40:33 +00:00
Services middleware and Gateway API filters on HTTP backends
This commit is contained in:
@@ -103,7 +103,7 @@ test-integration:
|
|||||||
#? test-gateway-api-conformance: Run the Gateway API conformance tests
|
#? test-gateway-api-conformance: Run the Gateway API conformance tests
|
||||||
test-gateway-api-conformance: build-image-dirty
|
test-gateway-api-conformance: build-image-dirty
|
||||||
# In case of a new Minor/Major version, the traefikVersion needs to be updated.
|
# In case of a new Minor/Major version, the traefikVersion needs to be updated.
|
||||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -tags gatewayAPIConformance -test.run GatewayAPIConformanceSuite -traefikVersion="v3.6" $(TESTFLAGS)
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -v -tags gatewayAPIConformance -test.run GatewayAPIConformanceSuite -traefikVersion="v3.7" $(TESTFLAGS)
|
||||||
|
|
||||||
.PHONY: test-knative-conformance
|
.PHONY: test-knative-conformance
|
||||||
#? test-knative-conformance: Run the Knative conformance tests
|
#? test-knative-conformance: Run the Knative conformance tests
|
||||||
|
|||||||
@@ -222,6 +222,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of
|
||||||
|
the referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -1232,6 +1251,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to
|
||||||
|
Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -2974,6 +3012,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -3211,6 +3268,24 @@ spec:
|
|||||||
Default value is -1, which means unlimited size.
|
Default value is -1, which means unlimited size.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to Middleware
|
||||||
|
resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced Middleware
|
||||||
|
resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
mirrorBody:
|
mirrorBody:
|
||||||
description: |-
|
description: |-
|
||||||
MirrorBody defines whether the body of the request should be mirrored.
|
MirrorBody defines whether the body of the request should be mirrored.
|
||||||
@@ -3298,6 +3373,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -3686,6 +3780,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
|
|||||||
@@ -223,6 +223,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of
|
||||||
|
the referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
|
|||||||
@@ -387,6 +387,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to
|
||||||
|
Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
|
|||||||
@@ -131,6 +131,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -368,6 +387,24 @@ spec:
|
|||||||
Default value is -1, which means unlimited size.
|
Default value is -1, which means unlimited size.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to Middleware
|
||||||
|
resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced Middleware
|
||||||
|
resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
mirrorBody:
|
mirrorBody:
|
||||||
description: |-
|
description: |-
|
||||||
MirrorBody defines whether the body of the request should be mirrored.
|
MirrorBody defines whether the body of the request should be mirrored.
|
||||||
@@ -455,6 +492,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -843,6 +899,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
|
|||||||
@@ -112,31 +112,33 @@
|
|||||||
[http.services.Service03.loadBalancer.responseForwarding]
|
[http.services.Service03.loadBalancer.responseForwarding]
|
||||||
flushInterval = "42s"
|
flushInterval = "42s"
|
||||||
[http.services.Service04]
|
[http.services.Service04]
|
||||||
[http.services.Service04.mirroring]
|
middlewares = ["foobar", "foobar"]
|
||||||
|
[http.services.Service05]
|
||||||
|
[http.services.Service05.mirroring]
|
||||||
service = "foobar"
|
service = "foobar"
|
||||||
mirrorBody = true
|
mirrorBody = true
|
||||||
maxBodySize = 42
|
maxBodySize = 42
|
||||||
|
|
||||||
[[http.services.Service04.mirroring.mirrors]]
|
[[http.services.Service05.mirroring.mirrors]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
percent = 42
|
percent = 42
|
||||||
|
|
||||||
[[http.services.Service04.mirroring.mirrors]]
|
[[http.services.Service05.mirroring.mirrors]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
percent = 42
|
percent = 42
|
||||||
[http.services.Service04.mirroring.healthCheck]
|
[http.services.Service05.mirroring.healthCheck]
|
||||||
[http.services.Service05]
|
[http.services.Service06]
|
||||||
[http.services.Service05.weighted]
|
[http.services.Service06.weighted]
|
||||||
|
|
||||||
[[http.services.Service05.weighted.services]]
|
[[http.services.Service06.weighted.services]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
weight = 42
|
weight = 42
|
||||||
|
|
||||||
[[http.services.Service05.weighted.services]]
|
[[http.services.Service06.weighted.services]]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
weight = 42
|
weight = 42
|
||||||
[http.services.Service05.weighted.sticky]
|
[http.services.Service06.weighted.sticky]
|
||||||
[http.services.Service05.weighted.sticky.cookie]
|
[http.services.Service06.weighted.sticky.cookie]
|
||||||
name = "foobar"
|
name = "foobar"
|
||||||
secure = true
|
secure = true
|
||||||
httpOnly = true
|
httpOnly = true
|
||||||
@@ -144,7 +146,7 @@
|
|||||||
maxAge = 42
|
maxAge = 42
|
||||||
path = "foobar"
|
path = "foobar"
|
||||||
domain = "foobar"
|
domain = "foobar"
|
||||||
[http.services.Service05.weighted.healthCheck]
|
[http.services.Service06.weighted.healthCheck]
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.Middleware01]
|
[http.middlewares.Middleware01]
|
||||||
[http.middlewares.Middleware01.addPrefix]
|
[http.middlewares.Middleware01.addPrefix]
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ http:
|
|||||||
flushInterval: 42s
|
flushInterval: 42s
|
||||||
serversTransport: foobar
|
serversTransport: foobar
|
||||||
Service04:
|
Service04:
|
||||||
|
middlewares:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
Service05:
|
||||||
mirroring:
|
mirroring:
|
||||||
service: foobar
|
service: foobar
|
||||||
mirrorBody: true
|
mirrorBody: true
|
||||||
@@ -130,7 +134,7 @@ http:
|
|||||||
- name: foobar
|
- name: foobar
|
||||||
percent: 42
|
percent: 42
|
||||||
healthCheck: {}
|
healthCheck: {}
|
||||||
Service05:
|
Service06:
|
||||||
weighted:
|
weighted:
|
||||||
services:
|
services:
|
||||||
- name: foobar
|
- name: foobar
|
||||||
|
|||||||
@@ -223,6 +223,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of
|
||||||
|
the referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -1233,6 +1252,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to
|
||||||
|
Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -2975,6 +3013,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -3212,6 +3269,24 @@ spec:
|
|||||||
Default value is -1, which means unlimited size.
|
Default value is -1, which means unlimited size.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references to Middleware
|
||||||
|
resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced Middleware
|
||||||
|
resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
mirrorBody:
|
mirrorBody:
|
||||||
description: |-
|
description: |-
|
||||||
MirrorBody defines whether the body of the request should be mirrored.
|
MirrorBody defines whether the body of the request should be mirrored.
|
||||||
@@ -3299,6 +3374,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
@@ -3687,6 +3781,25 @@ spec:
|
|||||||
- Service
|
- Service
|
||||||
- TraefikService
|
- TraefikService
|
||||||
type: string
|
type: string
|
||||||
|
middlewares:
|
||||||
|
description: Middlewares defines the list of references
|
||||||
|
to Middleware resources to apply to the service.
|
||||||
|
items:
|
||||||
|
description: MiddlewareRef is a reference to a Middleware
|
||||||
|
resource.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name defines the name of the referenced
|
||||||
|
Middleware resource.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace defines the namespace of the
|
||||||
|
referenced Middleware resource.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[api]
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
noColor = true
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
filename = "{{ .SelfFilename }}"
|
||||||
|
|
||||||
|
## dynamic configuration ##
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router1]
|
||||||
|
service = "service1"
|
||||||
|
rule = "Path(`/whoami`)"
|
||||||
|
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.add-header.headers.customRequestHeaders]
|
||||||
|
X-Custom-Header = "service-middleware-test"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.service1]
|
||||||
|
middlewares = ["add-header"]
|
||||||
|
[http.services.service1.loadBalancer]
|
||||||
|
[[http.services.service1.loadBalancer.servers]]
|
||||||
|
url = "{{ .Server }}"
|
||||||
+3
-3
@@ -8,7 +8,7 @@ implementation:
|
|||||||
organization: traefik
|
organization: traefik
|
||||||
project: traefik
|
project: traefik
|
||||||
url: https://traefik.io/
|
url: https://traefik.io/
|
||||||
version: v3.6
|
version: v3.7
|
||||||
kind: ConformanceReport
|
kind: ConformanceReport
|
||||||
mode: default
|
mode: default
|
||||||
profiles:
|
profiles:
|
||||||
@@ -30,12 +30,13 @@ profiles:
|
|||||||
result: success
|
result: success
|
||||||
statistics:
|
statistics:
|
||||||
Failed: 0
|
Failed: 0
|
||||||
Passed: 13
|
Passed: 15
|
||||||
Skipped: 0
|
Skipped: 0
|
||||||
supportedFeatures:
|
supportedFeatures:
|
||||||
- GatewayPort8080
|
- GatewayPort8080
|
||||||
- HTTPRouteBackendProtocolH2C
|
- HTTPRouteBackendProtocolH2C
|
||||||
- HTTPRouteBackendProtocolWebSocket
|
- HTTPRouteBackendProtocolWebSocket
|
||||||
|
- HTTPRouteBackendRequestHeaderModification
|
||||||
- HTTPRouteDestinationPortMatching
|
- HTTPRouteDestinationPortMatching
|
||||||
- HTTPRouteHostRewrite
|
- HTTPRouteHostRewrite
|
||||||
- HTTPRouteMethodMatching
|
- HTTPRouteMethodMatching
|
||||||
@@ -50,7 +51,6 @@ profiles:
|
|||||||
- GatewayHTTPListenerIsolation
|
- GatewayHTTPListenerIsolation
|
||||||
- GatewayInfrastructurePropagation
|
- GatewayInfrastructurePropagation
|
||||||
- GatewayStaticAddresses
|
- GatewayStaticAddresses
|
||||||
- HTTPRouteBackendRequestHeaderModification
|
|
||||||
- HTTPRouteBackendTimeout
|
- HTTPRouteBackendTimeout
|
||||||
- HTTPRouteCORS
|
- HTTPRouteCORS
|
||||||
- HTTPRouteNamedRouteRule
|
- HTTPRouteNamedRouteRule
|
||||||
@@ -2364,3 +2364,37 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() {
|
|||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SimpleSuite) TestServiceMiddleware() {
|
||||||
|
s.createComposeProject("base")
|
||||||
|
|
||||||
|
s.composeUp()
|
||||||
|
defer s.composeDown()
|
||||||
|
|
||||||
|
whoamiIP := s.getComposeServiceIP("whoami1")
|
||||||
|
|
||||||
|
file := s.adaptFile("fixtures/service_middleware.toml", struct {
|
||||||
|
Server string
|
||||||
|
}{Server: "http://" + whoamiIP})
|
||||||
|
|
||||||
|
s.traefikCmd(withConfigFile(file))
|
||||||
|
|
||||||
|
// Wait for Traefik to be ready
|
||||||
|
err := try.GetRequest("http://127.0.0.1:8080/api/http/services", 2*time.Second, try.BodyContains("service1"))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// Make a request and verify the middleware added the custom header
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(req)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||||
|
|
||||||
|
// Read the response body to check if the whoami service received the custom header
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// The whoami service should have received the X-Custom-Header that was added by the service middleware
|
||||||
|
assert.Contains(s.T(), string(body), "X-Custom-Header: service-middleware-test")
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ type Model struct {
|
|||||||
|
|
||||||
// Service holds a service configuration (can only be of one type at the same time).
|
// Service holds a service configuration (can only be of one type at the same time).
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||||
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
|
||||||
HighestRandomWeight *HighestRandomWeight `json:"highestRandomWeight,omitempty" toml:"highestRandomWeight,omitempty" yaml:"highestRandomWeight,omitempty" label:"-" export:"true"`
|
HighestRandomWeight *HighestRandomWeight `json:"highestRandomWeight,omitempty" toml:"highestRandomWeight,omitempty" yaml:"highestRandomWeight,omitempty" label:"-" export:"true"`
|
||||||
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
|
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
|
||||||
|
|||||||
@@ -1672,6 +1672,11 @@ func (in *ServersTransport) DeepCopy() *ServersTransport {
|
|||||||
// 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 *Service) DeepCopyInto(out *Service) {
|
func (in *Service) DeepCopyInto(out *Service) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Middlewares != nil {
|
||||||
|
in, out := &in.Middlewares, &out.Middlewares
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
if in.LoadBalancer != nil {
|
if in.LoadBalancer != nil {
|
||||||
in, out := &in.LoadBalancer, &out.LoadBalancer
|
in, out := &in.LoadBalancer, &out.LoadBalancer
|
||||||
*out = new(ServersLoadBalancer)
|
*out = new(ServersLoadBalancer)
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ const (
|
|||||||
typeName = "Chain"
|
typeName = "Chain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type chainBuilder interface {
|
type middlewareChainBuilder interface {
|
||||||
BuildChain(ctx context.Context, middlewares []string) *alice.Chain
|
BuildMiddlewareChain(ctx context.Context, middlewares []string) *alice.Chain
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a chain middleware.
|
// New creates a chain middleware.
|
||||||
func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder chainBuilder, name string) (http.Handler, error) {
|
func New(ctx context.Context, next http.Handler, config dynamic.Chain, builder middlewareChainBuilder, name string) (http.Handler, error) {
|
||||||
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
middlewares.GetLogger(ctx, name, typeName).Debug().Msg("Creating middleware")
|
||||||
|
|
||||||
middlewareChain := builder.BuildChain(ctx, config.Middlewares)
|
middlewareChain := builder.BuildMiddlewareChain(ctx, config.Middlewares)
|
||||||
return middlewareChain.Then(next)
|
return middlewareChain.Then(next)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: stripprefix
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
stripPrefix:
|
||||||
|
prefixes:
|
||||||
|
- /tobestripped
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: TraefikService
|
||||||
|
metadata:
|
||||||
|
name: test-weighted
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
weighted:
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
weight: 1
|
||||||
|
middlewares:
|
||||||
|
- name: stripprefix
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 12
|
||||||
|
services:
|
||||||
|
- name: test-weighted
|
||||||
|
kind: TraefikService
|
||||||
+14
@@ -37,6 +37,7 @@ type LoadBalancerSpecApplyConfiguration struct {
|
|||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
Kind *string `json:"kind,omitempty"`
|
Kind *string `json:"kind,omitempty"`
|
||||||
Namespace *string `json:"namespace,omitempty"`
|
Namespace *string `json:"namespace,omitempty"`
|
||||||
|
Middlewares []MiddlewareRefApplyConfiguration `json:"middlewares,omitempty"`
|
||||||
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
||||||
Port *intstr.IntOrString `json:"port,omitempty"`
|
Port *intstr.IntOrString `json:"port,omitempty"`
|
||||||
Scheme *string `json:"scheme,omitempty"`
|
Scheme *string `json:"scheme,omitempty"`
|
||||||
@@ -81,6 +82,19 @@ func (b *LoadBalancerSpecApplyConfiguration) WithNamespace(value string) *LoadBa
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMiddlewares adds the given value to the Middlewares field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the Middlewares field.
|
||||||
|
func (b *LoadBalancerSpecApplyConfiguration) WithMiddlewares(values ...*MiddlewareRefApplyConfiguration) *LoadBalancerSpecApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithMiddlewares")
|
||||||
|
}
|
||||||
|
b.Middlewares = append(b.Middlewares, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
||||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
// If called multiple times, the Sticky field is set to the value of the last call.
|
// If called multiple times, the Sticky field is set to the value of the last call.
|
||||||
|
|||||||
+13
@@ -70,6 +70,19 @@ func (b *MirroringApplyConfiguration) WithNamespace(value string) *MirroringAppl
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMiddlewares adds the given value to the Middlewares field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the Middlewares field.
|
||||||
|
func (b *MirroringApplyConfiguration) WithMiddlewares(values ...*MiddlewareRefApplyConfiguration) *MirroringApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithMiddlewares")
|
||||||
|
}
|
||||||
|
b.LoadBalancerSpecApplyConfiguration.Middlewares = append(b.LoadBalancerSpecApplyConfiguration.Middlewares, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
||||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
// If called multiple times, the Sticky field is set to the value of the last call.
|
// If called multiple times, the Sticky field is set to the value of the last call.
|
||||||
|
|||||||
+13
@@ -68,6 +68,19 @@ func (b *MirrorServiceApplyConfiguration) WithNamespace(value string) *MirrorSer
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMiddlewares adds the given value to the Middlewares field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the Middlewares field.
|
||||||
|
func (b *MirrorServiceApplyConfiguration) WithMiddlewares(values ...*MiddlewareRefApplyConfiguration) *MirrorServiceApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithMiddlewares")
|
||||||
|
}
|
||||||
|
b.LoadBalancerSpecApplyConfiguration.Middlewares = append(b.LoadBalancerSpecApplyConfiguration.Middlewares, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
||||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
// If called multiple times, the Sticky field is set to the value of the last call.
|
// If called multiple times, the Sticky field is set to the value of the last call.
|
||||||
|
|||||||
+13
@@ -67,6 +67,19 @@ func (b *ServiceApplyConfiguration) WithNamespace(value string) *ServiceApplyCon
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMiddlewares adds the given value to the Middlewares field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the Middlewares field.
|
||||||
|
func (b *ServiceApplyConfiguration) WithMiddlewares(values ...*MiddlewareRefApplyConfiguration) *ServiceApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithMiddlewares")
|
||||||
|
}
|
||||||
|
b.LoadBalancerSpecApplyConfiguration.Middlewares = append(b.LoadBalancerSpecApplyConfiguration.Middlewares, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
// WithSticky sets the Sticky field in the declarative configuration to the given value
|
||||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
// If called multiple times, the Sticky field is set to the value of the last call.
|
// If called multiple times, the Sticky field is set to the value of the last call.
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errorPage, errorPageService, err := p.createErrorPageMiddleware(client, middleware.Namespace, middleware.Spec.Errors)
|
errorPage, errorPageService, err := p.createErrorPageMiddleware(ctxMid, client, middleware.Namespace, middleware.Spec.Errors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msg("Error while reading error page middleware")
|
logger.Error().Err(err).Msg("Error while reading error page middleware")
|
||||||
continue
|
continue
|
||||||
@@ -645,7 +645,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
|||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *traefikv1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {
|
func (p *Provider) createErrorPageMiddleware(ctx context.Context, client Client, namespace string, errorPage *traefikv1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {
|
||||||
if errorPage == nil {
|
if errorPage == nil {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
@@ -663,7 +663,7 @@ func (p *Provider) createErrorPageMiddleware(client Client, namespace string, er
|
|||||||
allowEmptyServices: p.AllowEmptyServices,
|
allowEmptyServices: p.AllowEmptyServices,
|
||||||
}
|
}
|
||||||
|
|
||||||
balancerServerHTTP, err := cb.buildServersLB(namespace, errorPage.Service.LoadBalancerSpec)
|
balancerServerHTTP, err := cb.buildServersLB(ctx, namespace, errorPage.Service.LoadBalancerSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
|
|||||||
|
|
||||||
serviceKey := makeServiceKey(route.Match, ingressName)
|
serviceKey := makeServiceKey(route.Match, ingressName)
|
||||||
|
|
||||||
mds, err := p.makeMiddlewareKeys(ctx, ingressRoute.Namespace, route.Middlewares)
|
mds, err := makeMiddlewareKeys(ctx, ingressRoute.Namespace, route.Middlewares, p.AllowCrossNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msg("Failed to create middleware keys")
|
logger.Error().Err(err).Msg("Failed to create middleware keys")
|
||||||
continue
|
continue
|
||||||
@@ -172,13 +172,13 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
|
|||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace string, middlewares []traefikv1alpha1.MiddlewareRef) ([]string, error) {
|
func makeMiddlewareKeys(ctx context.Context, namespace string, middlewares []traefikv1alpha1.MiddlewareRef, allowCrossNamespace bool) ([]string, error) {
|
||||||
var mds []string
|
var mds []string
|
||||||
|
|
||||||
for _, mi := range middlewares {
|
for _, mi := range middlewares {
|
||||||
name := mi.Name
|
name := mi.Name
|
||||||
|
|
||||||
if !p.AllowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+providerName) {
|
if !allowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+providerName) {
|
||||||
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
|
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
|
||||||
// if the provider namespace kubernetescrd is used,
|
// if the provider namespace kubernetescrd is used,
|
||||||
// we don't allow this format to avoid cross namespace references.
|
// we don't allow this format to avoid cross namespace references.
|
||||||
@@ -196,10 +196,10 @@ func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace str
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := ingRouteNamespace
|
ns := namespace
|
||||||
if len(mi.Namespace) > 0 {
|
if len(mi.Namespace) > 0 {
|
||||||
if !isNamespaceAllowed(p.AllowCrossNamespace, ingRouteNamespace, mi.Namespace) {
|
if !isNamespaceAllowed(allowCrossNamespace, namespace, mi.Namespace) {
|
||||||
return nil, fmt.Errorf("middleware %s/%s is not in the IngressRoute namespace %s", mi.Namespace, mi.Name, ingRouteNamespace)
|
return nil, fmt.Errorf("middleware %s/%s is not in the parent namespace %s", mi.Namespace, mi.Name, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
ns = mi.Namespace
|
ns = mi.Namespace
|
||||||
@@ -333,6 +333,7 @@ func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tS
|
|||||||
Sticky: sticky,
|
Sticky: sticky,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +379,7 @@ func (c configBuilder) buildMirroring(ctx context.Context, tService *traefikv1al
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildServersLB creates the configuration for the load-balancer of servers defined by svc.
|
// buildServersLB creates the configuration for the load-balancer of servers defined by svc.
|
||||||
func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.LoadBalancerSpec) (*dynamic.Service, error) {
|
func (c configBuilder) buildServersLB(ctx context.Context, namespace string, svc traefikv1alpha1.LoadBalancerSpec) (*dynamic.Service, error) {
|
||||||
lb := &dynamic.ServersLoadBalancer{}
|
lb := &dynamic.ServersLoadBalancer{}
|
||||||
lb.SetDefaults()
|
lb.SetDefaults()
|
||||||
|
|
||||||
@@ -501,7 +502,16 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dynamic.Service{LoadBalancer: lb}, nil
|
service := &dynamic.Service{LoadBalancer: lb}
|
||||||
|
if len(svc.Middlewares) > 0 {
|
||||||
|
mds, err := makeMiddlewareKeys(ctx, namespace, svc.Middlewares, c.allowCrossNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not create middleware keys: %w", err)
|
||||||
|
}
|
||||||
|
service.Middlewares = mds
|
||||||
|
}
|
||||||
|
|
||||||
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c configBuilder) makeServersTransportKey(parentNamespace string, serversTransportName string) (string, error) {
|
func (c configBuilder) makeServersTransportKey(parentNamespace string, serversTransportName string) (string, error) {
|
||||||
@@ -687,7 +697,7 @@ func (c configBuilder) nameAndService(ctx context.Context, parentNamespace strin
|
|||||||
|
|
||||||
switch service.Kind {
|
switch service.Kind {
|
||||||
case "", "Service":
|
case "", "Service":
|
||||||
serversLB, err := c.buildServersLB(namespace, service)
|
serversLB, err := c.buildServersLB(ctx, namespace, service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3279,6 +3279,71 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "TraefikService with service middleware",
|
||||||
|
paths: []string{"services.yml", "with_traefik_service_middleware.yml"},
|
||||||
|
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{"web"},
|
||||||
|
Service: "default-test-weighted",
|
||||||
|
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||||
|
Priority: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{
|
||||||
|
"default-stripprefix": {
|
||||||
|
StripPrefix: &dynamic.StripPrefix{
|
||||||
|
Prefixes: []string{"/tobestripped"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default-test-weighted": {
|
||||||
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
|
Services: []dynamic.WRRService{
|
||||||
|
{
|
||||||
|
Name: "default-whoami-80",
|
||||||
|
Weight: pointer(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default-whoami-80": {
|
||||||
|
Middlewares: []string{"default-stripprefix"},
|
||||||
|
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: "one kube services in a highest random weight",
|
desc: "one kube services in a highest random weight",
|
||||||
paths: []string{"with_highest_random_weight.yml"},
|
paths: []string{"with_highest_random_weight.yml"},
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ type LoadBalancerSpec struct {
|
|||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
// Namespace defines the namespace of the referenced Kubernetes Service or TraefikService.
|
// Namespace defines the namespace of the referenced Kubernetes Service or TraefikService.
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
|
// Middlewares defines the list of references to Middleware resources to apply to the service.
|
||||||
|
Middlewares []MiddlewareRef `json:"middlewares,omitempty"`
|
||||||
// Sticky defines the sticky sessions configuration.
|
// Sticky defines the sticky sessions configuration.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/load-balancing/service/#sticky-sessions
|
// More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/load-balancing/service/#sticky-sessions
|
||||||
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
||||||
|
|||||||
@@ -685,6 +685,11 @@ func (in *IngressRouteUDPSpec) DeepCopy() *IngressRouteUDPSpec {
|
|||||||
// 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 *LoadBalancerSpec) DeepCopyInto(out *LoadBalancerSpec) {
|
func (in *LoadBalancerSpec) DeepCopyInto(out *LoadBalancerSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Middlewares != nil {
|
||||||
|
in, out := &in.Middlewares, &out.Middlewares
|
||||||
|
*out = make([]MiddlewareRef, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
if in.Sticky != nil {
|
if in.Sticky != nil {
|
||||||
in, out := &in.Sticky, &out.Sticky
|
in, out := &in.Sticky, &out.Sticky
|
||||||
*out = new(dynamic.Sticky)
|
*out = new(dynamic.Sticky)
|
||||||
|
|||||||
@@ -44,5 +44,6 @@ func extendedHTTPRouteFeatures() sets.Set[features.Feature] {
|
|||||||
features.HTTPRouteBackendProtocolH2CFeature,
|
features.HTTPRouteBackendProtocolH2CFeature,
|
||||||
features.HTTPRouteBackendProtocolWebSocketFeature,
|
features.HTTPRouteBackendProtocolWebSocketFeature,
|
||||||
features.HTTPRouteDestinationPortMatchingFeature,
|
features.HTTPRouteDestinationPortMatchingFeature,
|
||||||
|
features.HTTPRouteBackendRequestHeaderModificationFeature,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
kind: GatewayClass
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: my-gateway-class
|
||||||
|
spec:
|
||||||
|
controllerName: traefik.io/gateway-controller
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: Gateway
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: my-gateway
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
gatewayClassName: my-gateway-class
|
||||||
|
listeners:
|
||||||
|
- name: http
|
||||||
|
protocol: HTTP
|
||||||
|
port: 80
|
||||||
|
allowedRoutes:
|
||||||
|
kinds:
|
||||||
|
- kind: HTTPRoute
|
||||||
|
group: gateway.networking.k8s.io
|
||||||
|
namespaces:
|
||||||
|
from: Same
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: HTTPRoute
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: http-app-1
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: my-gateway
|
||||||
|
kind: Gateway
|
||||||
|
group: gateway.networking.k8s.io
|
||||||
|
hostnames:
|
||||||
|
- "foo.com"
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /bar
|
||||||
|
backendRefs:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
weight: 1
|
||||||
|
kind: Service
|
||||||
|
group: ""
|
||||||
|
filters:
|
||||||
|
- type: RequestHeaderModifier
|
||||||
|
requestHeaderModifier:
|
||||||
|
set:
|
||||||
|
- name: X-Foo
|
||||||
|
value: Bar
|
||||||
|
add:
|
||||||
|
- name: X-Bar
|
||||||
|
value: Foo
|
||||||
|
remove:
|
||||||
|
- X-Baz
|
||||||
@@ -140,6 +140,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, listener gatewayListener,
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
routerName := makeRouterName(rule, routeKey)
|
routerName := makeRouterName(rule, routeKey)
|
||||||
|
// TODO loadMiddlewares errors could change the condition.
|
||||||
router.Middlewares, err = p.loadMiddlewares(conf, route.Namespace, routerName, routeRule.Filters, match.Path)
|
router.Middlewares, err = p.loadMiddlewares(conf, route.Namespace, routerName, routeRule.Filters, match.Path)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
@@ -164,7 +165,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, listener gatewayListener,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
var serviceCondition *metav1.Condition
|
var serviceCondition *metav1.Condition
|
||||||
router.Service, serviceCondition = p.loadWRRService(ctx, listener, conf, routerName, routeRule, route)
|
router.Service, serviceCondition = p.loadWRRService(ctx, listener, conf, routerName, routeRule, route, match.Path)
|
||||||
if serviceCondition != nil {
|
if serviceCondition != nil {
|
||||||
condition = *serviceCondition
|
condition = *serviceCondition
|
||||||
}
|
}
|
||||||
@@ -179,7 +180,7 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, listener gatewayListener,
|
|||||||
return conf, condition
|
return conf, condition
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) loadWRRService(ctx context.Context, listener gatewayListener, conf *dynamic.Configuration, routeKey string, routeRule gatev1.HTTPRouteRule, route *gatev1.HTTPRoute) (string, *metav1.Condition) {
|
func (p *Provider) loadWRRService(ctx context.Context, listener gatewayListener, conf *dynamic.Configuration, routeKey string, routeRule gatev1.HTTPRouteRule, route *gatev1.HTTPRoute, pathMatch *gatev1.HTTPPathMatch) (string, *metav1.Condition) {
|
||||||
name := routeKey + "-wrr"
|
name := routeKey + "-wrr"
|
||||||
if _, ok := conf.HTTP.Services[name]; ok {
|
if _, ok := conf.HTTP.Services[name]; ok {
|
||||||
return name, nil
|
return name, nil
|
||||||
@@ -188,7 +189,9 @@ func (p *Provider) loadWRRService(ctx context.Context, listener gatewayListener,
|
|||||||
var wrr dynamic.WeightedRoundRobin
|
var wrr dynamic.WeightedRoundRobin
|
||||||
var condition *metav1.Condition
|
var condition *metav1.Condition
|
||||||
for _, backendRef := range routeRule.BackendRefs {
|
for _, backendRef := range routeRule.BackendRefs {
|
||||||
svcName, errCondition := p.loadService(ctx, listener, conf, route, backendRef)
|
// TODO in loadService we need to always return a non-nil serviceName even when there is an error which is not the
|
||||||
|
// usual defacto.
|
||||||
|
svcName, errCondition := p.loadService(ctx, listener, conf, route, backendRef, pathMatch)
|
||||||
weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1)))
|
weight := ptr.To(int(ptr.Deref(backendRef.Weight, 1)))
|
||||||
if errCondition != nil {
|
if errCondition != nil {
|
||||||
log.Ctx(ctx).Error().
|
log.Ctx(ctx).Error().
|
||||||
@@ -215,7 +218,7 @@ func (p *Provider) loadWRRService(ctx context.Context, listener gatewayListener,
|
|||||||
|
|
||||||
// loadService returns a dynamic.Service config corresponding to the given gatev1.HTTPBackendRef.
|
// loadService returns a dynamic.Service config corresponding to the given gatev1.HTTPBackendRef.
|
||||||
// Note that the returned dynamic.Service config can be nil (for cross-provider, internal services, and backendFunc).
|
// Note that the returned dynamic.Service config can be nil (for cross-provider, internal services, and backendFunc).
|
||||||
func (p *Provider) loadService(ctx context.Context, listener gatewayListener, conf *dynamic.Configuration, route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef) (string, *metav1.Condition) {
|
func (p *Provider) loadService(ctx context.Context, listener gatewayListener, conf *dynamic.Configuration, route *gatev1.HTTPRoute, backendRef gatev1.HTTPBackendRef, pathMatch *gatev1.HTTPPathMatch) (string, *metav1.Condition) {
|
||||||
kind := ptr.Deref(backendRef.Kind, kindService)
|
kind := ptr.Deref(backendRef.Kind, kindService)
|
||||||
|
|
||||||
group := groupCore
|
group := groupCore
|
||||||
@@ -241,6 +244,19 @@ func (p *Provider) loadService(ctx context.Context, listener gatewayListener, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
middlewares, err := p.loadMiddlewares(conf, namespace, serviceName, backendRef.Filters, pathMatch)
|
||||||
|
if err != nil {
|
||||||
|
return serviceName, &metav1.Condition{
|
||||||
|
Type: string(gatev1.RouteConditionResolvedRefs),
|
||||||
|
Status: metav1.ConditionFalse,
|
||||||
|
ObservedGeneration: route.Generation,
|
||||||
|
LastTransitionTime: metav1.Now(),
|
||||||
|
Reason: string(gatev1.RouteReasonInvalidKind),
|
||||||
|
Message: fmt.Sprintf("Cannot load filters on HTTPBackendRef %s/%s/%s/%s: %s", group, kind, namespace, backendRef.Name, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO may be we could incorporate this "ignored" case into the loadHTTPBackendRef.
|
||||||
if group != groupCore || kind != kindService {
|
if group != groupCore || kind != kindService {
|
||||||
name, service, err := p.loadHTTPBackendRef(namespace, backendRef)
|
name, service, err := p.loadHTTPBackendRef(namespace, backendRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -255,6 +271,7 @@ func (p *Provider) loadService(ctx context.Context, listener gatewayListener, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if service != nil {
|
if service != nil {
|
||||||
|
service.Middlewares = middlewares
|
||||||
conf.HTTP.Services[name] = service
|
conf.HTTP.Services[name] = service
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +303,7 @@ func (p *Provider) loadService(ctx context.Context, listener gatewayListener, co
|
|||||||
conf.HTTP.ServersTransports[serviceName] = st
|
conf.HTTP.ServersTransports[serviceName] = st
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.HTTP.Services[serviceName] = &dynamic.Service{LoadBalancer: lb}
|
conf.HTTP.Services[serviceName] = &dynamic.Service{LoadBalancer: lb, Middlewares: middlewares}
|
||||||
|
|
||||||
return serviceName, nil
|
return serviceName, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1917,6 +1917,77 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||||||
TLS: &dynamic.TLSConfiguration{},
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Simple HTTPRoute, backend filter request header modifier",
|
||||||
|
paths: []string{"services.yml", "httproute/backend_filter_request_header_modifier.yml"},
|
||||||
|
entryPoints: map[string]Entrypoint{"web": {
|
||||||
|
Address: ":80",
|
||||||
|
}},
|
||||||
|
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{
|
||||||
|
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-99f4d29346f69ccb6fc3": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-99f4d29346f69ccb6fc3-wrr",
|
||||||
|
Rule: "Host(`foo.com`) && (Path(`/bar`) || PathPrefix(`/bar/`))",
|
||||||
|
Priority: 10408,
|
||||||
|
RuleSyntax: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{
|
||||||
|
"default-whoami-http-requestheadermodifier-0": {
|
||||||
|
RequestHeaderModifier: &dynamic.HeaderModifier{
|
||||||
|
Set: map[string]string{"X-Foo": "Bar"},
|
||||||
|
Add: map[string]string{"X-Bar": "Foo"},
|
||||||
|
Remove: []string{"X-Baz"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-99f4d29346f69ccb6fc3-wrr": {
|
||||||
|
Weighted: &dynamic.WeightedRoundRobin{
|
||||||
|
Services: []dynamic.WRRService{
|
||||||
|
{
|
||||||
|
Name: "default-whoami-http-80",
|
||||||
|
Weight: ptr.To(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default-whoami-http-80": {
|
||||||
|
Middlewares: []string{"default-whoami-http-requestheadermodifier-0"},
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Strategy: dynamic.BalancerStrategyWRR,
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.1:80",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.2:80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: ptr.To(true),
|
||||||
|
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||||
|
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "Simple HTTPRoute, redirect HTTP to HTTPS",
|
desc: "Simple HTTPRoute, redirect HTTP to HTTPS",
|
||||||
paths: []string{"services.yml", "httproute/filter_http_to_https.yml"},
|
paths: []string{"services.yml", "httproute/filter_http_to_https.yml"},
|
||||||
@@ -1954,6 +2025,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-364ce6ec04c3d49b19c4-wrr": {
|
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-364ce6ec04c3d49b19c4-wrr": {
|
||||||
Weighted: &dynamic.WeightedRoundRobin{},
|
Weighted: &dynamic.WeightedRoundRobin{},
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ type ServiceIng struct {
|
|||||||
ServersScheme string `json:"serversScheme,omitempty"`
|
ServersScheme string `json:"serversScheme,omitempty"`
|
||||||
ServersTransport string `json:"serversTransport,omitempty"`
|
ServersTransport string `json:"serversTransport,omitempty"`
|
||||||
PassHostHeader *bool `json:"passHostHeader"`
|
PassHostHeader *bool `json:"passHostHeader"`
|
||||||
|
Middlewares []string `json:"middlewares,omitempty"`
|
||||||
Sticky *dynamic.Sticky `json:"sticky,omitempty" label:"allowEmpty"`
|
Sticky *dynamic.Sticky `json:"sticky,omitempty" label:"allowEmpty"`
|
||||||
NativeLB *bool `json:"nativeLB,omitempty"`
|
NativeLB *bool `json:"nativeLB,omitempty"`
|
||||||
NodePortLB bool `json:"nodePortLB,omitempty"`
|
NodePortLB bool `json:"nodePortLB,omitempty"`
|
||||||
|
|||||||
@@ -161,6 +161,18 @@ func Test_parseServiceConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "service middlewares annotation",
|
||||||
|
annotations: map[string]string{
|
||||||
|
"traefik.ingress.kubernetes.io/service.middlewares": "middleware1,middleware2",
|
||||||
|
},
|
||||||
|
expected: &ServiceConfig{
|
||||||
|
Service: &ServiceIng{
|
||||||
|
Middlewares: []string{"middleware1", "middleware2"},
|
||||||
|
PassHostHeader: pointer(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "empty map",
|
desc: "empty map",
|
||||||
annotations: map[string]string{},
|
annotations: map[string]string{},
|
||||||
|
|||||||
@@ -563,6 +563,7 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
|
|||||||
|
|
||||||
if svcConfig != nil && svcConfig.Service != nil {
|
if svcConfig != nil && svcConfig.Service != nil {
|
||||||
svc.LoadBalancer.Sticky = svcConfig.Service.Sticky
|
svc.LoadBalancer.Sticky = svcConfig.Service.Sticky
|
||||||
|
svc.Middlewares = svcConfig.Service.Middlewares
|
||||||
|
|
||||||
if svcConfig.Service.PassHostHeader != nil {
|
if svcConfig.Service.PassHostHeader != nil {
|
||||||
svc.LoadBalancer.PassHostHeader = svcConfig.Service.PassHostHeader
|
svc.LoadBalancer.PassHostHeader = svcConfig.Service.PassHostHeader
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ func NewBuilder(configs map[string]*runtime.MiddlewareInfo, serviceBuilder servi
|
|||||||
return &Builder{configs: configs, serviceBuilder: serviceBuilder, pluginBuilder: pluginBuilder}
|
return &Builder{configs: configs, serviceBuilder: serviceBuilder, pluginBuilder: pluginBuilder}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildChain creates a middleware chain.
|
// BuildMiddlewareChain creates a middleware chain.
|
||||||
func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *alice.Chain {
|
func (b *Builder) BuildMiddlewareChain(ctx context.Context, middlewares []string) *alice.Chain {
|
||||||
chain := alice.New()
|
chain := alice.New()
|
||||||
for _, name := range middlewares {
|
for _, name := range middlewares {
|
||||||
middlewareName := provider.GetQualifiedName(ctx, name)
|
middlewareName := provider.GetQualifiedName(ctx, name)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func TestBuilder_BuildChainNilConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
||||||
|
|
||||||
chain := middlewaresBuilder.BuildChain(t.Context(), []string{"empty"})
|
chain := middlewaresBuilder.BuildMiddlewareChain(t.Context(), []string{"empty"})
|
||||||
_, err := chain.Then(nil)
|
_, err := chain.Then(nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ func TestBuilder_BuildChainNonExistentChain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
||||||
|
|
||||||
chain := middlewaresBuilder.BuildChain(t.Context(), []string{"empty"})
|
chain := middlewaresBuilder.BuildMiddlewareChain(t.Context(), []string{"empty"})
|
||||||
_, err := chain.Then(nil)
|
_, err := chain.Then(nil)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func TestBuilder_BuildChainWithContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
builder := NewBuilder(rtConf.Middlewares, nil, nil)
|
builder := NewBuilder(rtConf.Middlewares, nil, nil)
|
||||||
|
|
||||||
result := builder.BuildChain(ctx, test.buildChain)
|
result := builder.BuildMiddlewareChain(ctx, test.buildChain)
|
||||||
|
|
||||||
handlers, err := result.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))
|
handlers, err := result.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))
|
||||||
if test.expectedError != nil {
|
if test.expectedError != nil {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import (
|
|||||||
|
|
||||||
const maxUserPriority = math.MaxInt - 1000
|
const maxUserPriority = math.MaxInt - 1000
|
||||||
|
|
||||||
type middlewareBuilder interface {
|
type middlewareChainBuilder interface {
|
||||||
BuildChain(ctx context.Context, names []string) *alice.Chain
|
BuildMiddlewareChain(ctx context.Context, names []string) *alice.Chain
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceManager interface {
|
type serviceManager interface {
|
||||||
@@ -42,7 +42,7 @@ type Manager struct {
|
|||||||
routerHandlers map[string]http.Handler
|
routerHandlers map[string]http.Handler
|
||||||
serviceManager serviceManager
|
serviceManager serviceManager
|
||||||
observabilityMgr *middleware.ObservabilityMgr
|
observabilityMgr *middleware.ObservabilityMgr
|
||||||
middlewaresBuilder middlewareBuilder
|
middlewaresBuilder middlewareChainBuilder
|
||||||
conf *runtime.Configuration
|
conf *runtime.Configuration
|
||||||
tlsManager *tls.Manager
|
tlsManager *tls.Manager
|
||||||
parser httpmuxer.SyntaxParser
|
parser httpmuxer.SyntaxParser
|
||||||
@@ -51,7 +51,7 @@ type Manager struct {
|
|||||||
// NewManager creates a new Manager.
|
// NewManager creates a new Manager.
|
||||||
func NewManager(conf *runtime.Configuration,
|
func NewManager(conf *runtime.Configuration,
|
||||||
serviceManager serviceManager,
|
serviceManager serviceManager,
|
||||||
middlewaresBuilder middlewareBuilder,
|
middlewaresBuilder middlewareChainBuilder,
|
||||||
observabilityMgr *middleware.ObservabilityMgr,
|
observabilityMgr *middleware.ObservabilityMgr,
|
||||||
tlsManager *tls.Manager,
|
tlsManager *tls.Manager,
|
||||||
parser httpmuxer.SyntaxParser,
|
parser httpmuxer.SyntaxParser,
|
||||||
@@ -372,7 +372,7 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
mHandler := m.middlewaresBuilder.BuildChain(ctx, router.Middlewares)
|
mHandler := m.middlewaresBuilder.BuildMiddlewareChain(ctx, router.Middlewares)
|
||||||
|
|
||||||
return chain.Extend(*mHandler).Then(nextHandler)
|
return chain.Extend(*mHandler).Then(nextHandler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2000,7 +2000,7 @@ func (m *mockServiceManager) LaunchHealthCheck(_ context.Context) {}
|
|||||||
|
|
||||||
type mockMiddlewareBuilder struct{}
|
type mockMiddlewareBuilder struct{}
|
||||||
|
|
||||||
func (m *mockMiddlewareBuilder) BuildChain(_ context.Context, _ []string) *alice.Chain {
|
func (m *mockMiddlewareBuilder) BuildMiddlewareChain(_ context.Context, _ []string) *alice.Chain {
|
||||||
chain := alice.New()
|
chain := alice.New()
|
||||||
return &chain
|
return &chain
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ func (f *RouterFactory) CreateRouters(rtConf *runtime.Configuration) (map[string
|
|||||||
|
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, f.pluginBuilder)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, f.pluginBuilder)
|
||||||
|
|
||||||
|
serviceManager.SetMiddlewareChainBuilder(middlewaresBuilder)
|
||||||
|
|
||||||
routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.observabilityMgr, f.tlsManager, f.parser)
|
routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.observabilityMgr, f.tlsManager, f.parser)
|
||||||
|
|
||||||
routerManager.ParseRouterTree()
|
routerManager.ParseRouterTree()
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ type ServiceBuilder interface {
|
|||||||
BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error)
|
BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type middlewareChainBuilder interface {
|
||||||
|
BuildMiddlewareChain(ctx context.Context, middlewares []string) *alice.Chain
|
||||||
|
}
|
||||||
|
|
||||||
// Manager The service manager.
|
// Manager The service manager.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
routinePool *safe.Pool
|
routinePool *safe.Pool
|
||||||
@@ -56,10 +60,11 @@ type Manager struct {
|
|||||||
proxyBuilder ProxyBuilder
|
proxyBuilder ProxyBuilder
|
||||||
serviceBuilders []ServiceBuilder
|
serviceBuilders []ServiceBuilder
|
||||||
|
|
||||||
services map[string]http.Handler
|
services map[string]http.Handler
|
||||||
configs map[string]*runtime.ServiceInfo
|
configs map[string]*runtime.ServiceInfo
|
||||||
healthCheckers map[string]*healthcheck.ServiceHealthChecker
|
healthCheckers map[string]*healthcheck.ServiceHealthChecker
|
||||||
rand *rand.Rand // For the initial shuffling of load-balancers.
|
rand *rand.Rand // For the initial shuffling of load-balancers.
|
||||||
|
middlewareChainBuilder middlewareChainBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new Manager.
|
// NewManager creates a new Manager.
|
||||||
@@ -77,6 +82,11 @@ func NewManager(configs map[string]*runtime.ServiceInfo, observabilityMgr *middl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMiddlewareChainBuilder sets the MiddlewareChainBuilder.
|
||||||
|
func (m *Manager) SetMiddlewareChainBuilder(middlewareChainBuilder middlewareChainBuilder) {
|
||||||
|
m.middlewareChainBuilder = middlewareChainBuilder
|
||||||
|
}
|
||||||
|
|
||||||
// BuildHTTP Creates a http.Handler for a service configuration.
|
// BuildHTTP Creates a http.Handler for a service configuration.
|
||||||
func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error) {
|
func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error) {
|
||||||
serviceName = provider.GetQualifiedName(rootCtx, serviceName)
|
serviceName = provider.GetQualifiedName(rootCtx, serviceName)
|
||||||
@@ -113,7 +123,7 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.H
|
|||||||
value := reflect.ValueOf(*conf.Service)
|
value := reflect.ValueOf(*conf.Service)
|
||||||
var count int
|
var count int
|
||||||
for i := range value.NumField() {
|
for i := range value.NumField() {
|
||||||
if !value.Field(i).IsNil() {
|
if value.Type().Field(i).Name != "Middlewares" && !value.Field(i).IsNil() {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,9 +183,22 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.H
|
|||||||
return nil, sErr
|
return nil, sErr
|
||||||
}
|
}
|
||||||
|
|
||||||
m.services[serviceName] = lb
|
if len(conf.Middlewares) > 0 {
|
||||||
|
if m.middlewareChainBuilder == nil {
|
||||||
|
// This should happen only in tests.
|
||||||
|
return nil, errors.New("chain builder not defined")
|
||||||
|
}
|
||||||
|
chain := m.middlewareChainBuilder.BuildMiddlewareChain(ctx, conf.Middlewares)
|
||||||
|
var err error
|
||||||
|
lb, err = chain.Then(lb)
|
||||||
|
if err != nil {
|
||||||
|
conf.AddError(err, true)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return lb, nil
|
m.services[serviceName] = lb
|
||||||
|
return m.services[serviceName], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LaunchHealthCheck launches the health checks.
|
// LaunchHealthCheck launches the health checks.
|
||||||
|
|||||||
Reference in New Issue
Block a user