Preserve HTTPRoute filters order

This commit is contained in:
Kevin Pollet 2024-10-21 09:54:04 +02:00 committed by GitHub
parent ef5aa129c7
commit eeb99c3536
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 46 additions and 19 deletions

View file

@ -54,4 +54,9 @@ spec:
extensionRef: extensionRef:
group: traefik.io group: traefik.io
kind: Middleware kind: Middleware
name: my-middleware name: my-first-middleware
- type: ExtensionRef
extensionRef:
group: traefik.io
kind: Middleware
name: my-second-middleware

View file

@ -301,36 +301,52 @@ func (p *Provider) loadHTTPBackendRef(namespace string, backendRef gatev1.HTTPBa
} }
func (p *Provider) loadMiddlewares(conf *dynamic.Configuration, namespace, routerName string, filters []gatev1.HTTPRouteFilter, pathMatch *gatev1.HTTPPathMatch) ([]string, error) { func (p *Provider) loadMiddlewares(conf *dynamic.Configuration, namespace, routerName string, filters []gatev1.HTTPRouteFilter, pathMatch *gatev1.HTTPPathMatch) ([]string, error) {
type namedMiddleware struct {
Name string
Config *dynamic.Middleware
}
pm := ptr.Deref(pathMatch, gatev1.HTTPPathMatch{ pm := ptr.Deref(pathMatch, gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchPathPrefix), Type: ptr.To(gatev1.PathMatchPathPrefix),
Value: ptr.To("/"), Value: ptr.To("/"),
}) })
middlewares := make(map[string]*dynamic.Middleware) var middlewares []namedMiddleware
for i, filter := range filters { for i, filter := range filters {
name := fmt.Sprintf("%s-%s-%d", routerName, strings.ToLower(string(filter.Type)), i) name := fmt.Sprintf("%s-%s-%d", routerName, strings.ToLower(string(filter.Type)), i)
switch filter.Type { switch filter.Type {
case gatev1.HTTPRouteFilterRequestRedirect: case gatev1.HTTPRouteFilterRequestRedirect:
middlewares[name] = createRequestRedirect(filter.RequestRedirect, pm) middlewares = append(middlewares, namedMiddleware{
name,
createRequestRedirect(filter.RequestRedirect, pm),
})
case gatev1.HTTPRouteFilterRequestHeaderModifier: case gatev1.HTTPRouteFilterRequestHeaderModifier:
middlewares[name] = createRequestHeaderModifier(filter.RequestHeaderModifier) middlewares = append(middlewares, namedMiddleware{
name,
createRequestHeaderModifier(filter.RequestHeaderModifier),
})
case gatev1.HTTPRouteFilterExtensionRef: case gatev1.HTTPRouteFilterExtensionRef:
name, middleware, err := p.loadHTTPRouteFilterExtensionRef(namespace, filter.ExtensionRef) name, middleware, err := p.loadHTTPRouteFilterExtensionRef(namespace, filter.ExtensionRef)
if err != nil { if err != nil {
return nil, fmt.Errorf("loading ExtensionRef filter %s: %w", filter.Type, err) return nil, fmt.Errorf("loading ExtensionRef filter %s: %w", filter.Type, err)
} }
middlewares = append(middlewares, namedMiddleware{
middlewares[name] = middleware name,
middleware,
})
case gatev1.HTTPRouteFilterURLRewrite: case gatev1.HTTPRouteFilterURLRewrite:
var err error
middleware, err := createURLRewrite(filter.URLRewrite, pm) middleware, err := createURLRewrite(filter.URLRewrite, pm)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid filter %s: %w", filter.Type, err) return nil, fmt.Errorf("invalid filter %s: %w", filter.Type, err)
} }
middlewares[name] = middleware middlewares = append(middlewares, namedMiddleware{
name,
middleware,
})
default: default:
// As per the spec: https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional // As per the spec: https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional
@ -342,12 +358,11 @@ func (p *Provider) loadMiddlewares(conf *dynamic.Configuration, namespace, route
} }
var middlewareNames []string var middlewareNames []string
for name, middleware := range middlewares { for _, m := range middlewares {
if middleware != nil { if m.Config != nil {
conf.HTTP.Middlewares[name] = middleware conf.HTTP.Middlewares[m.Name] = m.Config
} }
middlewareNames = append(middlewareNames, m.Name)
middlewareNames = append(middlewareNames, name)
} }
return middlewareNames, nil return middlewareNames, nil

View file

@ -2431,7 +2431,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
entryPoints map[string]Entrypoint entryPoints map[string]Entrypoint
}{ }{
{ {
desc: "HTTPRoute with ExtensionRef filter", desc: "ExtensionRef filter",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{ groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) { traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, nil, nil return namespace + "-" + name, nil, nil
@ -2459,7 +2459,10 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
Rule: "Host(`foo.com`) && Path(`/bar`)", Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008, Priority: 100008,
RuleSyntax: "v3", RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"}, Middlewares: []string{
"default-my-first-middleware",
"default-my-second-middleware",
},
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
@ -2497,7 +2500,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
}, },
}, },
{ {
desc: "HTTPRoute with ExtensionRef filter and create middleware", desc: "ExtensionRef filter with middleware creation",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{ groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) { traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, &dynamic.Middleware{Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, nil return namespace + "-" + name, &dynamic.Middleware{Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, nil
@ -2525,11 +2528,15 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
Rule: "Host(`foo.com`) && Path(`/bar`)", Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008, Priority: 100008,
RuleSyntax: "v3", RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"}, Middlewares: []string{
"default-my-first-middleware",
"default-my-second-middleware",
},
}, },
}, },
Middlewares: map[string]*dynamic.Middleware{ Middlewares: map[string]*dynamic.Middleware{
"default-my-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, "default-my-first-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
"default-my-second-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
}, },
Services: map[string]*dynamic.Service{ Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": { "default-http-app-1-my-gateway-web-0-wrr": {
@ -2565,7 +2572,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
}, },
}, },
{ {
desc: "ExtensionRef filter: Unknown", desc: "Unknown ExtensionRef filter",
entryPoints: map[string]Entrypoint{"web": { entryPoints: map[string]Entrypoint{"web": {
Address: ":80", Address: ":80",
}}, }},