mirror of
https://github.com/traefik/traefik.git
synced 2026-10-28 08:36:10 +08:00
Support HTTPRoute retry
This commit is contained in:
1 parent
b46d3ea648
commit
855f81ab09
12 files changed
+441
-22
No files matched your search
@@ -385,6 +385,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
|
||||
| <a id="opt-providers-kubernetesgateway-namespaces" href="#opt-providers-kubernetesgateway-namespaces" title="#opt-providers-kubernetesgateway-namespaces">providers.kubernetesgateway.namespaces</a> | Kubernetes namespaces. | |
|
||||
| <a id="opt-providers-kubernetesgateway-nativelbbydefault" href="#opt-providers-kubernetesgateway-nativelbbydefault" title="#opt-providers-kubernetesgateway-nativelbbydefault">providers.kubernetesgateway.nativelbbydefault</a> | Defines whether to use Native Kubernetes load-balancing by default. | false |
|
||||
| <a id="opt-providers-kubernetesgateway-qps" href="#opt-providers-kubernetesgateway-qps" title="#opt-providers-kubernetesgateway-qps">providers.kubernetesgateway.qps</a> | Defines the maximum QPS to the Kubernetes API server. Setting this to a negative value will disable client-side ratelimiting. | 50 |
|
||||
| <a id="opt-providers-kubernetesgateway-retrymaxrequestbodybytes" href="#opt-providers-kubernetesgateway-retrymaxrequestbodybytes" title="#opt-providers-kubernetesgateway-retrymaxrequestbodybytes">providers.kubernetesgateway.retrymaxrequestbodybytes</a> | Defines the maximum request body size (in bytes) buffered for HTTPRoute retries. If negative, the limit is disabled. | 2097152 |
|
||||
| <a id="opt-providers-kubernetesgateway-statusaddress-hostname" href="#opt-providers-kubernetesgateway-statusaddress-hostname" title="#opt-providers-kubernetesgateway-statusaddress-hostname">providers.kubernetesgateway.statusaddress.hostname</a> | Hostname used for Kubernetes Gateway status address. | |
|
||||
| <a id="opt-providers-kubernetesgateway-statusaddress-ip" href="#opt-providers-kubernetesgateway-statusaddress-ip" title="#opt-providers-kubernetesgateway-statusaddress-ip">providers.kubernetesgateway.statusaddress.ip</a> | IP used to set Kubernetes Gateway status address. | |
|
||||
| <a id="opt-providers-kubernetesgateway-statusaddress-service" href="#opt-providers-kubernetesgateway-statusaddress-service" title="#opt-providers-kubernetesgateway-statusaddress-service">providers.kubernetesgateway.statusaddress.service</a> | Published Kubernetes Service to copy status addresses from. | |
|
||||
|
||||
+1
@@ -89,6 +89,7 @@ providers:
|
||||
| <a id="opt-providers-kubernetesGateway-gateways0-namespace" href="#opt-providers-kubernetesGateway-gateways0-namespace" title="#opt-providers-kubernetesGateway-gateways0-namespace">`providers.kubernetesGateway.gateways[0].namespace`</a> | Gateway namespace. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-throttleDuration" href="#opt-providers-kubernetesGateway-throttleDuration" title="#opt-providers-kubernetesGateway-throttleDuration">`providers.kubernetesGateway.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
|
||||
| <a id="opt-providers-kubernetesGateway-nativeLBByDefault" href="#opt-providers-kubernetesGateway-nativeLBByDefault" title="#opt-providers-kubernetesGateway-nativeLBByDefault">`providers.kubernetesGateway.nativeLBByDefault`</a> | Defines whether to use Native Kubernetes load-balancing mode by default. For more information, please check out the `traefik.io/service.nativelb` service annotation documentation. | false | No |
|
||||
| <a id="opt-providers-kubernetesGateway-retryMaxRequestBodyBytes" href="#opt-providers-kubernetesGateway-retryMaxRequestBodyBytes" title="#opt-providers-kubernetesGateway-retryMaxRequestBodyBytes">`providers.kubernetesGateway.retryMaxRequestBodyBytes`</a> | Defines the maximum request body size (in bytes) buffered for HTTPRoute retries.<br />If negative, the limit is disabled.<br />A request with a larger body is forwarded without retry. | 2097152 | No |
|
||||
| <a id="opt-providers-kubernetesGateway-statusAddress-hostname" href="#opt-providers-kubernetesGateway-statusAddress-hostname" title="#opt-providers-kubernetesGateway-statusAddress-hostname">`providers.kubernetesGateway.`<br />`statusAddress.hostname`</a> | Hostname copied to the Gateway `status.addresses`. | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-statusAddress-ip" href="#opt-providers-kubernetesGateway-statusAddress-ip" title="#opt-providers-kubernetesGateway-statusAddress-ip">`providers.kubernetesGateway.`<br />`statusAddress.ip`</a> | IP address copied to the Gateway `status.addresses`, and currently only supports one IP value (IPv4 or IPv6). | "" | No |
|
||||
| <a id="opt-providers-kubernetesGateway-statusAddress-service-namespace" href="#opt-providers-kubernetesGateway-statusAddress-service-namespace" title="#opt-providers-kubernetesGateway-statusAddress-service-namespace">`providers.kubernetesGateway.`<br />`statusAddress.service.namespace`</a> | The namespace of the Kubernetes service to copy status addresses from.<br />When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the Gateway `status.addresses`. | "" | No |
|
||||
|
||||
@@ -200,6 +200,7 @@
|
||||
throttleDuration = "42s"
|
||||
experimentalChannel = true
|
||||
nativeLBByDefault = true
|
||||
retryMaxRequestBodyBytes = 42
|
||||
[providers.kubernetesGateway.statusAddress]
|
||||
ip = "foobar"
|
||||
hostname = "foobar"
|
||||
|
||||
@@ -226,6 +226,7 @@ providers:
|
||||
name: foobar
|
||||
namespace: foobar
|
||||
nativeLBByDefault: true
|
||||
retryMaxRequestBodyBytes: 42
|
||||
rest:
|
||||
insecure: true
|
||||
consulCatalog:
|
||||
|
||||
+5
-3
@@ -55,7 +55,7 @@ profiles:
|
||||
result: success
|
||||
statistics:
|
||||
Failed: 0
|
||||
Passed: 56
|
||||
Passed: 60
|
||||
Skipped: 0
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
@@ -89,6 +89,8 @@ profiles:
|
||||
- HTTPRouteQueryParamMatching
|
||||
- HTTPRouteRequestTimeout
|
||||
- HTTPRouteResponseHeaderModification
|
||||
- HTTPRouteRetryCodes
|
||||
- HTTPRouteRetryConnectionError
|
||||
- HTTPRouteSchemeRedirect
|
||||
- ListenerSet
|
||||
unsupportedFeatures:
|
||||
@@ -100,8 +102,6 @@ profiles:
|
||||
- HTTPRouteRequestMirror
|
||||
- HTTPRouteRequestMultipleMirrors
|
||||
- HTTPRouteRequestPercentageMirror
|
||||
- HTTPRouteRetryCodes
|
||||
- HTTPRouteRetryConnectionError
|
||||
name: GATEWAY-HTTP
|
||||
summary: Core tests succeeded. Extended tests succeeded.
|
||||
- core:
|
||||
@@ -176,3 +176,5 @@ succeededProvisionalTests:
|
||||
- GatewayPreserveForeignConditions
|
||||
- HTTPRouteBackendURLRewrite
|
||||
- HTTPRoutePreserveForeignStatus
|
||||
- HTTPRouteRetryWithBackendTimeout
|
||||
- HTTPRouteRetryWithRequestTimeout
|
||||
+5
-3
@@ -68,7 +68,7 @@ profiles:
|
||||
- GatewayInvalidFrontendClientCertificateValidation
|
||||
statistics:
|
||||
Failed: 0
|
||||
Passed: 49
|
||||
Passed: 53
|
||||
Skipped: 5
|
||||
supportedFeatures:
|
||||
- BackendTLSPolicy
|
||||
@@ -100,6 +100,8 @@ profiles:
|
||||
- HTTPRouteQueryParamMatching
|
||||
- HTTPRouteRequestTimeout
|
||||
- HTTPRouteResponseHeaderModification
|
||||
- HTTPRouteRetryCodes
|
||||
- HTTPRouteRetryConnectionError
|
||||
- HTTPRouteSchemeRedirect
|
||||
- ListenerSet
|
||||
unsupportedFeatures:
|
||||
@@ -113,8 +115,6 @@ profiles:
|
||||
- HTTPRouteRequestMirror
|
||||
- HTTPRouteRequestMultipleMirrors
|
||||
- HTTPRouteRequestPercentageMirror
|
||||
- HTTPRouteRetryCodes
|
||||
- HTTPRouteRetryConnectionError
|
||||
name: GATEWAY-HTTP
|
||||
summary: Core tests partially succeeded with 1 test skips. Extended tests partially
|
||||
succeeded with 5 test skips.
|
||||
@@ -197,3 +197,5 @@ succeededProvisionalTests:
|
||||
- GatewayPreserveForeignConditions
|
||||
- HTTPRouteBackendURLRewrite
|
||||
- HTTPRoutePreserveForeignStatus
|
||||
- HTTPRouteRetryWithBackendTimeout
|
||||
- HTTPRouteRetryWithRequestTimeout
|
||||
@@ -74,6 +74,8 @@ func extendedHTTPRouteFeatures() sets.Set[features.Feature] {
|
||||
features.HTTPRouteRequestTimeoutFeature,
|
||||
features.HTTPRouteBackendTimeoutFeature,
|
||||
features.HTTPRouteBackendURLRewriteFeature,
|
||||
features.HTTPRouteRetryCodesFeature,
|
||||
features.HTTPRouteRetryConnectionErrorFeature,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
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: # Use GatewayClass defaults for listener definition.
|
||||
- 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:
|
||||
- "example.org"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
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
|
||||
retry:
|
||||
codes:
|
||||
- 500
|
||||
- 503
|
||||
attempts: 3
|
||||
backoff: 100ms
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
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: # Use GatewayClass defaults for listener definition.
|
||||
- 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:
|
||||
- "example.org"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
retry: {}
|
||||
@@ -158,6 +158,11 @@ func (p *Provider) loadHTTPRouteConfiguration(ctx context.Context, gatewayName,
|
||||
}
|
||||
}
|
||||
|
||||
var retry *dynamic.Middleware
|
||||
if routeRule.Retry != nil {
|
||||
retry = createRetry(ctx, routeRule.Retry, p.RetryMaxRequestBodyBytes)
|
||||
}
|
||||
|
||||
for _, match := range routeRule.Matches {
|
||||
rule, priority := buildMatchRule(hostnames, match)
|
||||
router := dynamic.Router{
|
||||
@@ -223,6 +228,13 @@ func (p *Provider) loadHTTPRouteConfiguration(ctx context.Context, gatewayName,
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && retry != nil {
|
||||
// The retry middleware comes last, so that only the call to the backend is retried.
|
||||
retryName := routerName + "-retry"
|
||||
routerConf.HTTP.Middlewares[retryName] = retry
|
||||
router.Middlewares = append(router.Middlewares, retryName)
|
||||
}
|
||||
|
||||
p.applyRouterTransform(ctx, &router, route)
|
||||
|
||||
routerConf.HTTP.Routers[routerName] = &router
|
||||
@@ -1088,6 +1100,30 @@ func createCORS(filter *gatev1.HTTPCORSFilter) *dynamic.Middleware {
|
||||
}
|
||||
}
|
||||
|
||||
func createRetry(ctx context.Context, retry *gatev1.HTTPRouteRetry, maxRequestBodyBytes int64) *dynamic.Middleware {
|
||||
// The Gateway API attempts are the number of retries,
|
||||
// whereas the Traefik ones also count the initial request, hence the +1.
|
||||
r := &dynamic.Retry{
|
||||
Attempts: ptr.Deref(retry.Attempts, 1) + 1,
|
||||
MaxRequestBodyBytes: &maxRequestBodyBytes,
|
||||
}
|
||||
|
||||
for _, code := range retry.Codes {
|
||||
r.Status = append(r.Status, strconv.Itoa(int(code)))
|
||||
}
|
||||
|
||||
if retry.Backoff != nil {
|
||||
// The CRD validation guarantees a valid GEP-2257 duration string.
|
||||
if backoff, err := time.ParseDuration(string(*retry.Backoff)); err != nil {
|
||||
log.Ctx(ctx).Error().Err(err).Msg("Ignoring HTTPRoute retry.backoff: invalid duration")
|
||||
} else {
|
||||
r.InitialInterval = ptypes.Duration(backoff)
|
||||
}
|
||||
}
|
||||
|
||||
return &dynamic.Middleware{Retry: r}
|
||||
}
|
||||
|
||||
func getHTTPServiceProtocol(portSpec corev1.ServicePort) (string, error) {
|
||||
if portSpec.Protocol != corev1.ProtocolTCP {
|
||||
return "", errors.New("only TCP protocol is supported")
|
||||
|
||||
@@ -92,13 +92,14 @@ type Provider struct {
|
||||
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
|
||||
GatewayClass string `description:"Name of the GatewayClass to watch for. If empty, all GatewayClasses are processed." json:"gatewayClass,omitempty" toml:"gatewayClass,omitempty" yaml:"gatewayClass,omitempty" export:"true"`
|
||||
// Deprecated: please use the GatewayClass option instead.
|
||||
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses (Deprecated, please use the GatewayClass option instead)." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
||||
Gateways []NamespacedName `description:"Scopes the provider to specific Gateways." json:"gateways,omitempty" toml:"gateways,omitempty" yaml:"gateways,omitempty" export:"true"`
|
||||
ThrottleDuration ptypes.Duration `description:"Kubernetes refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
|
||||
ExperimentalChannel bool `description:"Toggles Experimental Channel resources support. Requires the Experimental Channel CRDs." json:"experimentalChannel,omitempty" toml:"experimentalChannel,omitempty" yaml:"experimentalChannel,omitempty" export:"true"`
|
||||
StatusAddress *StatusAddress `description:"Defines the Kubernetes Gateway status address." json:"statusAddress,omitempty" toml:"statusAddress,omitempty" yaml:"statusAddress,omitempty" export:"true"`
|
||||
NativeLBByDefault bool `description:"Defines whether to use Native Kubernetes load-balancing by default." json:"nativeLBByDefault,omitempty" toml:"nativeLBByDefault,omitempty" yaml:"nativeLBByDefault,omitempty" export:"true"`
|
||||
CrossProviderNamespaces []string `description:"List of namespaces from which Gateway API routes are allowed to declare TraefikService backendRef references." json:"crossProviderNamespaces,omitempty" toml:"crossProviderNamespaces,omitempty" yaml:"crossProviderNamespaces,omitempty" export:"true"`
|
||||
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses (Deprecated, please use the GatewayClass option instead)." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
||||
Gateways []NamespacedName `description:"Scopes the provider to specific Gateways." json:"gateways,omitempty" toml:"gateways,omitempty" yaml:"gateways,omitempty" export:"true"`
|
||||
ThrottleDuration ptypes.Duration `description:"Kubernetes refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
|
||||
ExperimentalChannel bool `description:"Toggles Experimental Channel resources support. Requires the Experimental Channel CRDs." json:"experimentalChannel,omitempty" toml:"experimentalChannel,omitempty" yaml:"experimentalChannel,omitempty" export:"true"`
|
||||
StatusAddress *StatusAddress `description:"Defines the Kubernetes Gateway status address." json:"statusAddress,omitempty" toml:"statusAddress,omitempty" yaml:"statusAddress,omitempty" export:"true"`
|
||||
NativeLBByDefault bool `description:"Defines whether to use Native Kubernetes load-balancing by default." json:"nativeLBByDefault,omitempty" toml:"nativeLBByDefault,omitempty" yaml:"nativeLBByDefault,omitempty" export:"true"`
|
||||
CrossProviderNamespaces []string `description:"List of namespaces from which Gateway API routes are allowed to declare TraefikService backendRef references." json:"crossProviderNamespaces,omitempty" toml:"crossProviderNamespaces,omitempty" yaml:"crossProviderNamespaces,omitempty" export:"true"`
|
||||
RetryMaxRequestBodyBytes int64 `description:"Defines the maximum request body size (in bytes) buffered for HTTPRoute retries. If negative, the limit is disabled." json:"retryMaxRequestBodyBytes,omitempty" toml:"retryMaxRequestBodyBytes,omitempty" yaml:"retryMaxRequestBodyBytes,omitempty" export:"true"`
|
||||
|
||||
EntryPoints map[string]Entrypoint `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||
|
||||
@@ -114,6 +115,7 @@ type Provider struct {
|
||||
func (p *Provider) SetDefaults() {
|
||||
p.QPS = 50 // the default value for the QPS is 10x the default Kubernetes client QPS value.
|
||||
p.Burst = 100 // the default value for the Burst is 10x the default Kubernetes client Burst value.
|
||||
p.RetryMaxRequestBodyBytes = dynamic.RetryDefaultMaxRequestBodyBytes
|
||||
}
|
||||
|
||||
// Entrypoint defines the available entry points.
|
||||
|
||||
@@ -220,12 +220,13 @@ func TestGatewayScoping(t *testing.T) {
|
||||
|
||||
func TestLoadHTTPRoutes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ingressClass string
|
||||
paths []string
|
||||
expected *dynamic.Configuration
|
||||
entryPoints map[string]Entrypoint
|
||||
nativeLB bool
|
||||
desc string
|
||||
ingressClass string
|
||||
paths []string
|
||||
expected *dynamic.Configuration
|
||||
entryPoints map[string]Entrypoint
|
||||
nativeLB bool
|
||||
retryMaxRequestBodyBytes int64
|
||||
}{
|
||||
{
|
||||
desc: "Empty",
|
||||
@@ -2880,6 +2881,255 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, retry",
|
||||
paths: []string{"services.yml", "httproute/with_retry.yml"},
|
||||
retryMaxRequestBodyBytes: dynamic.RetryDefaultMaxRequestBodyBytes,
|
||||
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{
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr",
|
||||
Rule: `Host("example.org") && PathPrefix("/")`,
|
||||
Priority: 13,
|
||||
RuleSyntax: "default",
|
||||
Middlewares: []string{"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-requestheadermodifier-0", "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-requestheadermodifier-0": {
|
||||
RequestHeaderModifier: &dynamic.HeaderModifier{
|
||||
Set: map[string]string{"X-Foo": "Bar"},
|
||||
Add: map[string]string{"X-Bar": "Foo"},
|
||||
Remove: []string{"X-Baz"},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry": {
|
||||
Retry: &dynamic.Retry{
|
||||
Attempts: 4,
|
||||
Status: []string{"500", "503"},
|
||||
InitialInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
MaxRequestBodyBytes: new(dynamic.RetryDefaultMaxRequestBodyBytes),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-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: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, retry with maxRequestBodyBytes",
|
||||
paths: []string{"services.yml", "httproute/with_retry.yml"},
|
||||
retryMaxRequestBodyBytes: 1024,
|
||||
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{
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr",
|
||||
Rule: `Host("example.org") && PathPrefix("/")`,
|
||||
Priority: 13,
|
||||
RuleSyntax: "default",
|
||||
Middlewares: []string{"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-requestheadermodifier-0", "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-requestheadermodifier-0": {
|
||||
RequestHeaderModifier: &dynamic.HeaderModifier{
|
||||
Set: map[string]string{"X-Foo": "Bar"},
|
||||
Add: map[string]string{"X-Bar": "Foo"},
|
||||
Remove: []string{"X-Baz"},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry": {
|
||||
Retry: &dynamic.Retry{
|
||||
Attempts: 4,
|
||||
Status: []string{"500", "503"},
|
||||
InitialInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
MaxRequestBodyBytes: new(int64(1024)),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-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: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, retry with defaults",
|
||||
paths: []string{"services.yml", "httproute/with_retry_empty.yml"},
|
||||
retryMaxRequestBodyBytes: dynamic.RetryDefaultMaxRequestBodyBytes,
|
||||
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{
|
||||
"listener-web-http-5b3226d4ebd42b7200f1": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: `Host("*")`,
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664": {
|
||||
ParentRefs: []string{"listener-web-http-5b3226d4ebd42b7200f1"},
|
||||
Service: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr",
|
||||
Rule: `Host("example.org") && PathPrefix("/")`,
|
||||
Priority: 13,
|
||||
RuleSyntax: "default",
|
||||
Middlewares: []string{"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-retry": {
|
||||
Retry: &dynamic.Retry{
|
||||
Attempts: 2,
|
||||
MaxRequestBodyBytes: new(dynamic.RetryDefaultMaxRequestBodyBytes),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-0",
|
||||
Weight: new(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-c683caccb22c43e5e664-svc-default-whoami-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: new(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Options: map[string]tls.Options{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, response header modifier",
|
||||
paths: []string{"services.yml", "httproute/filter_response_header_modifier.yml"},
|
||||
@@ -4894,9 +5144,10 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
||||
}
|
||||
|
||||
p := Provider{
|
||||
EntryPoints: test.entryPoints,
|
||||
NativeLBByDefault: test.nativeLB,
|
||||
client: client,
|
||||
EntryPoints: test.entryPoints,
|
||||
NativeLBByDefault: test.nativeLB,
|
||||
RetryMaxRequestBodyBytes: test.retryMaxRequestBodyBytes,
|
||||
client: client,
|
||||
}
|
||||
|
||||
conf, _, err := p.loadConfigurationFromGateways(t.Context())
|
||||
|
||||
Reference in new issue
Block a user