From c0a2e6b4b6511071317c91bc4f922aba1c8a6038 Mon Sep 17 00:00:00 2001 From: Kevin Pollet Date: Thu, 30 May 2024 09:14:04 +0200 Subject: [PATCH] Compute HTTPRoute priorities Co-authored-by: Romain --- integration/k8s_conformance_test.go | 4 - integration/testdata/rawdata-gateway.json | 24 +- pkg/provider/kubernetes/gateway/httproute.go | 144 +++++--- .../kubernetes/gateway/httproute_test.go | 287 ++++++++-------- .../kubernetes/gateway/kubernetes_test.go | 317 ++++++++++-------- 5 files changed, 429 insertions(+), 347 deletions(-) diff --git a/integration/k8s_conformance_test.go b/integration/k8s_conformance_test.go index 3ba562b2c..1e0c5d96b 100644 --- a/integration/k8s_conformance_test.go +++ b/integration/k8s_conformance_test.go @@ -199,12 +199,8 @@ func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() { RunTest: *k8sConformanceRunTest, // Until the feature are all supported, following tests are skipped. SkipTests: []string{ - tests.HTTPRouteListenerHostnameMatching.ShortName, tests.HTTPRouteInvalidCrossNamespaceParentRef.ShortName, - tests.HTTPRouteMatchingAcrossRoutes.ShortName, tests.HTTPRoutePartiallyInvalidViaInvalidReferenceGrant.ShortName, - tests.HTTPRoutePathMatchOrder.ShortName, - tests.HTTPRouteHeaderMatching.ShortName, tests.HTTPRouteReferenceGrant.ShortName, }, } diff --git a/integration/testdata/rawdata-gateway.json b/integration/testdata/rawdata-gateway.json index 08bd34802..d321d987f 100644 --- a/integration/testdata/rawdata-gateway.json +++ b/integration/testdata/rawdata-gateway.json @@ -30,27 +30,27 @@ "traefik" ] }, - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06@kubernetesgateway": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27@kubernetesgateway": { "entryPoints": [ "web" ], - "service": "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - "rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)", + "service": "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + "rule": "Host(`foo.com`) \u0026\u0026 (Path(`/bar`))", "ruleSyntax": "v3", - "priority": 31, + "priority": 99997, "status": "enabled", "using": [ "web" ] }, - "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06@kubernetesgateway": { + "default-http-app-1-my-https-gateway-websecure-af4b9876d1fe36359e27@kubernetesgateway": { "entryPoints": [ "websecure" ], - "service": "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06-wrr", - "rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)", + "service": "default-http-app-1-my-https-gateway-websecure-af4b9876d1fe36359e27-wrr", + "rule": "Host(`foo.com`) \u0026\u0026 (Path(`/bar`))", "ruleSyntax": "v3", - "priority": 31, + "priority": 99997, "tls": {}, "status": "enabled", "using": [ @@ -96,7 +96,7 @@ "dashboard@internal" ] }, - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr@kubernetesgateway": { "weighted": { "services": [ { @@ -107,10 +107,10 @@ }, "status": "enabled", "usedBy": [ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06@kubernetesgateway" + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27@kubernetesgateway" ] }, - "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": { + "default-http-app-1-my-https-gateway-websecure-af4b9876d1fe36359e27-wrr@kubernetesgateway": { "weighted": { "services": [ { @@ -121,7 +121,7 @@ }, "status": "enabled", "usedBy": [ - "default-http-app-1-my-https-gateway-websecure-1c0cf64bde37d9d0df06@kubernetesgateway" + "default-http-app-1-my-https-gateway-websecure-af4b9876d1fe36359e27@kubernetesgateway" ] }, "default-whoami-80@kubernetesgateway": { diff --git a/pkg/provider/kubernetes/gateway/httproute.go b/pkg/provider/kubernetes/gateway/httproute.go index 3410764d9..86664ee5f 100644 --- a/pkg/provider/kubernetes/gateway/httproute.go +++ b/pkg/provider/kubernetes/gateway/httproute.go @@ -128,12 +128,12 @@ func (p *Provider) loadHTTPRoute(ctx context.Context, client Client, listener ga }, } - hostRule := hostRule(hostnames) - for _, routeRule := range route.Spec.Rules { + rule, priority := buildRouterRule(hostnames, routeRule.Matches) router := dynamic.Router{ RuleSyntax: "v3", - Rule: routerRule(routeRule, hostRule), + Rule: rule, + Priority: priority, EntryPoints: []string{listener.EPName}, } if listener.Protocol == gatev1.HTTPSProtocolType { @@ -418,12 +418,17 @@ func loadHTTPServers(client Client, namespace string, backendRef gatev1.HTTPBack return lb, nil } -func hostRule(hostnames []gatev1.Hostname) string { +func buildHostRule(hostnames []gatev1.Hostname) (string, int) { var rules []string + var priority int for _, hostname := range hostnames { host := string(hostname) + if priority < len(host) { + priority = len(host) + } + wildcard := strings.Count(host, "*") if wildcard == 0 { rules = append(rules, fmt.Sprintf("Host(`%s`)", host)) @@ -436,86 +441,123 @@ func hostRule(hostnames []gatev1.Hostname) string { switch len(rules) { case 0: - return "" + return "", 0 case 1: - return rules[0] + return rules[0], priority default: - return fmt.Sprintf("(%s)", strings.Join(rules, " || ")) + return fmt.Sprintf("(%s)", strings.Join(rules, " || ")), priority } } -func routerRule(routeRule gatev1.HTTPRouteRule, hostRule string) string { - var rule string +// buildRouterRule builds the route rule and computes its priority. +// The current priority computing is rather naive but aims to fulfill Conformance tests suite requirement. +// The priority is computed to match the following precedence order: +// +// * "Exact" path match. (+100000) +// * "Prefix" path match with largest number of characters. (+10000) PathRegex (+1000) +// * Method match. (not implemented) +// * Largest number of header matches. (+100 each) or with PathRegex (+10 each) +// * Largest number of query param matches. (not implemented) +// +// In case of multiple matches for a route, the maximum priority among all matches is retain. +func buildRouterRule(hostnames []gatev1.Hostname, routeMatches []gatev1.HTTPRouteMatch) (string, int) { var matchesRules []string + var maxPriority int - for _, match := range routeRule.Matches { + for _, match := range routeMatches { path := ptr.Deref(match.Path, gatev1.HTTPPathMatch{ Type: ptr.To(gatev1.PathMatchPathPrefix), Value: ptr.To("/"), }) - pathType := ptr.Deref(path.Type, gatev1.PathMatchPathPrefix) - pathValue := ptr.Deref(path.Value, "/") + var priority int var matchRules []string - switch pathType { - case gatev1.PathMatchExact: - matchRules = append(matchRules, fmt.Sprintf("Path(`%s`)", pathValue)) - case gatev1.PathMatchPathPrefix: - matchRules = append(matchRules, buildPathMatchPathPrefixRule(pathValue)) - case gatev1.PathMatchRegularExpression: - matchRules = append(matchRules, fmt.Sprintf("PathRegexp(`%s`)", pathValue)) - } - matchRules = append(matchRules, headerRules(match.Headers)...) + pathRule, pathPriority := buildPathRule(path) + matchRules = append(matchRules, pathRule) + priority += pathPriority + + headerRules, headersPriority := buildHeaderRules(match.Headers) + matchRules = append(matchRules, headerRules...) + priority += headersPriority + matchesRules = append(matchesRules, strings.Join(matchRules, " && ")) - } - // If no matches are specified, the default is a prefix - // path match on "/", which has the effect of matching every - // HTTP request. - if len(routeRule.Matches) == 0 { - matchesRules = append(matchesRules, "PathPrefix(`/`)") - } - - if hostRule != "" { - if len(matchesRules) == 0 { - return hostRule + if priority > maxPriority { + maxPriority = priority } - rule += hostRule + " && " } - if len(matchesRules) == 1 { - return rule + matchesRules[0] + hostRule, hostPriority := buildHostRule(hostnames) + + matchesRulesStr := strings.Join(matchesRules, " || ") + + if hostRule == "" && matchesRulesStr == "" { + return "PathPrefix(`/`)", 1 } - if len(rule) == 0 { - return strings.Join(matchesRules, " || ") + if hostRule != "" && matchesRulesStr == "" { + return hostRule, hostPriority } - return rule + "(" + strings.Join(matchesRules, " || ") + ")" + // Enforce that, at the same priority, + // the route with fewer matches (more specific) matches first. + maxPriority -= len(matchesRules) * 10 + if maxPriority < 1 { + maxPriority = 1 + } + + if hostRule == "" { + return matchesRulesStr, maxPriority + } + + // A route with a host should match over the same route with no host. + maxPriority += hostPriority + return hostRule + " && " + "(" + matchesRulesStr + ")", maxPriority } -func headerRules(headers []gatev1.HTTPHeaderMatch) []string { - var headerRules []string +func buildPathRule(pathMatch gatev1.HTTPPathMatch) (string, int) { + pathType := ptr.Deref(pathMatch.Type, gatev1.PathMatchPathPrefix) + pathValue := ptr.Deref(pathMatch.Value, "/") + + switch pathType { + case gatev1.PathMatchExact: + return fmt.Sprintf("Path(`%s`)", pathValue), 100000 + + case gatev1.PathMatchPathPrefix: + // PathPrefix(`/`) rule is a catch-all, + // here we ensure it would be evaluated last. + if pathValue == "/" { + return "PathPrefix(`/`)", 1 + } + + pv := strings.TrimSuffix(pathValue, "/") + return fmt.Sprintf("(Path(`%[1]s`) || PathPrefix(`%[1]s/`))", pv), 10000 + len(pathValue)*100 + + case gatev1.PathMatchRegularExpression: + return fmt.Sprintf("PathRegexp(`%s`)", pathValue), 1000 + len(pathValue)*100 + + default: + return "PathPrefix(`/`)", 1 + } +} + +func buildHeaderRules(headers []gatev1.HTTPHeaderMatch) ([]string, int) { + var rules []string + var priority int for _, header := range headers { typ := ptr.Deref(header.Type, gatev1.HeaderMatchExact) switch typ { case gatev1.HeaderMatchExact: - headerRules = append(headerRules, fmt.Sprintf("Header(`%s`,`%s`)", header.Name, header.Value)) + rules = append(rules, fmt.Sprintf("Header(`%s`,`%s`)", header.Name, header.Value)) + priority += 100 case gatev1.HeaderMatchRegularExpression: - headerRules = append(headerRules, fmt.Sprintf("HeaderRegexp(`%s`,`%s`)", header.Name, header.Value)) + rules = append(rules, fmt.Sprintf("HeaderRegexp(`%s`,`%s`)", header.Name, header.Value)) + priority += 10 } } - return headerRules -} -func buildPathMatchPathPrefixRule(path string) string { - if path == "/" { - return "PathPrefix(`/`)" - } - - path = strings.TrimSuffix(path, "/") - return fmt.Sprintf("(Path(`%[1]s`) || PathPrefix(`%[1]s/`))", path) + return rules, priority } // createRequestHeaderModifier does not enforce/check the configuration, diff --git a/pkg/provider/kubernetes/gateway/httproute_test.go b/pkg/provider/kubernetes/gateway/httproute_test.go index 2698acfdb..9e9833e40 100644 --- a/pkg/provider/kubernetes/gateway/httproute_test.go +++ b/pkg/provider/kubernetes/gateway/httproute_test.go @@ -8,15 +8,16 @@ import ( gatev1 "sigs.k8s.io/gateway-api/apis/v1" ) -func Test_hostRule(t *testing.T) { +func Test_buildHostRule(t *testing.T) { testCases := []struct { - desc string - hostnames []gatev1.Hostname - expectedRule string - expectErr bool + desc string + hostnames []gatev1.Hostname + expectedRule string + expectedPriority int + expectErr bool }{ { - desc: "Empty rule and matches", + desc: "Empty (should not happen)", expectedRule: "", }, { @@ -24,7 +25,8 @@ func Test_hostRule(t *testing.T) { hostnames: []gatev1.Hostname{ "Foo", }, - expectedRule: "Host(`Foo`)", + expectedRule: "Host(`Foo`)", + expectedPriority: 3, }, { desc: "Multiple Hosts", @@ -33,7 +35,8 @@ func Test_hostRule(t *testing.T) { "Bar", "Bir", }, - expectedRule: "(Host(`Foo`) || Host(`Bar`) || Host(`Bir`))", + expectedRule: "(Host(`Foo`) || Host(`Bar`) || Host(`Bir`))", + expectedPriority: 3, }, { desc: "Several Host and wildcard", @@ -42,14 +45,16 @@ func Test_hostRule(t *testing.T) { "bar.foo", "foo.foo", }, - expectedRule: "(HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`) || Host(`bar.foo`) || Host(`foo.foo`))", + expectedRule: "(HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`) || Host(`bar.foo`) || Host(`foo.foo`))", + expectedPriority: 9, }, { desc: "Host with wildcard", hostnames: []gatev1.Hostname{ "*.bar.foo", }, - expectedRule: "HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`)", + expectedRule: "HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.foo$`)", + expectedPriority: 9, }, } @@ -57,216 +62,209 @@ func Test_hostRule(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - rule := hostRule(test.hostnames) + rule, priority := buildHostRule(test.hostnames) assert.Equal(t, test.expectedRule, rule) + assert.Equal(t, test.expectedPriority, priority) }) } } -func Test_routerRule(t *testing.T) { +func Test_buildRouterRule(t *testing.T) { testCases := []struct { - desc string - routeRule gatev1.HTTPRouteRule - hostRule string - expectedRule string - expectedError bool + desc string + routeMatches []gatev1.HTTPRouteMatch + hostnames []gatev1.Hostname + expectedRule string + expectedPriority int + expectedError bool }{ { - desc: "Empty rule and matches", - expectedRule: "PathPrefix(`/`)", + desc: "Empty rule and matches ", + expectedRule: "PathPrefix(`/`)", + expectedPriority: 1, }, { - desc: "One Host rule without matches", - hostRule: "Host(`foo.com`)", - expectedRule: "Host(`foo.com`) && PathPrefix(`/`)", + desc: "One Host rule without matches", + hostnames: []gatev1.Hostname{"foo.com"}, + expectedRule: "Host(`foo.com`)", + expectedPriority: 7, }, { desc: "One HTTPRouteMatch with nil HTTPHeaderMatch", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: ptr.To(gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchPathPrefix), - Value: ptr.To("/"), - }), - Headers: nil, - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: ptr.To(gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchPathPrefix), + Value: ptr.To("/"), + }), + Headers: nil, }, }, - expectedRule: "PathPrefix(`/`)", + expectedRule: "PathPrefix(`/`)", + expectedPriority: 1, }, { desc: "One HTTPRouteMatch with nil HTTPHeaderMatch Type", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: ptr.To(gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchPathPrefix), - Value: ptr.To("/"), - }), - Headers: []gatev1.HTTPHeaderMatch{ - {Name: "foo", Value: "bar"}, - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: ptr.To(gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchPathPrefix), + Value: ptr.To("/"), + }), + Headers: []gatev1.HTTPHeaderMatch{ + {Name: "foo", Value: "bar"}, }, }, }, - expectedRule: "PathPrefix(`/`) && Header(`foo`,`bar`)", + expectedRule: "PathPrefix(`/`) && Header(`foo`,`bar`)", + expectedPriority: 91, }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - {Path: nil}, - }, + routeMatches: []gatev1.HTTPRouteMatch{ + {Path: nil}, }, - expectedRule: "PathPrefix(`/`)", + expectedRule: "PathPrefix(`/`)", + expectedPriority: 1, }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch Type", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: nil, - Value: ptr.To("/foo/"), - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: nil, + Value: ptr.To("/foo/"), }, }, }, - expectedRule: "(Path(`/foo`) || PathPrefix(`/foo/`))", + expectedRule: "(Path(`/foo`) || PathPrefix(`/foo/`))", + expectedPriority: 10490, }, { desc: "One HTTPRouteMatch with nil HTTPPathMatch Values", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: nil, - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: nil, }, }, }, - expectedRule: "Path(`/`)", + expectedRule: "Path(`/`)", + expectedPriority: 99990, }, { desc: "One Path in matches", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), }, }, }, - expectedRule: "Path(`/foo/`)", + expectedRule: "Path(`/foo/`)", + expectedPriority: 99990, }, { desc: "One Path in matches and another empty", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), }, - {}, }, + {}, }, - expectedRule: "Path(`/foo/`) || PathPrefix(`/`)", + expectedRule: "Path(`/foo/`) || PathPrefix(`/`)", + expectedPriority: 99980, }, { desc: "Path OR Header rules", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), }, - { - Headers: []gatev1.HTTPHeaderMatch{ - { - Type: ptr.To(gatev1.HeaderMatchExact), - Name: "my-header", - Value: "foo", - }, + }, + { + Headers: []gatev1.HTTPHeaderMatch{ + { + Type: ptr.To(gatev1.HeaderMatchExact), + Name: "my-header", + Value: "foo", }, }, }, }, - expectedRule: "Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`)", + expectedRule: "Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`)", + expectedPriority: 99980, }, { desc: "Path && Header rules", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, - Headers: []gatev1.HTTPHeaderMatch{ - { - Type: ptr.To(gatev1.HeaderMatchExact), - Name: "my-header", - Value: "foo", - }, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), + }, + Headers: []gatev1.HTTPHeaderMatch{ + { + Type: ptr.To(gatev1.HeaderMatchExact), + Name: "my-header", + Value: "foo", }, }, }, }, - expectedRule: "Path(`/foo/`) && Header(`my-header`,`foo`)", + expectedRule: "Path(`/foo/`) && Header(`my-header`,`foo`)", + expectedPriority: 100090, }, { - desc: "Host && Path && Header rules", - hostRule: "Host(`foo.com`)", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, - Headers: []gatev1.HTTPHeaderMatch{ - { - Type: ptr.To(gatev1.HeaderMatchExact), - Name: "my-header", - Value: "foo", - }, + desc: "Host && Path && Header rules", + hostnames: []gatev1.Hostname{"foo.com"}, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), + }, + Headers: []gatev1.HTTPHeaderMatch{ + { + Type: ptr.To(gatev1.HeaderMatchExact), + Name: "my-header", + Value: "foo", }, }, }, }, - expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Header(`my-header`,`foo`)", + expectedRule: "Host(`foo.com`) && (Path(`/foo/`) && Header(`my-header`,`foo`))", + expectedPriority: 100097, }, { - desc: "Host && (Path || Header) rules", - hostRule: "Host(`foo.com`)", - routeRule: gatev1.HTTPRouteRule{ - Matches: []gatev1.HTTPRouteMatch{ - { - Path: &gatev1.HTTPPathMatch{ - Type: ptr.To(gatev1.PathMatchExact), - Value: ptr.To("/foo/"), - }, + desc: "Host && (Path || Header) rules", + hostnames: []gatev1.Hostname{"foo.com"}, + routeMatches: []gatev1.HTTPRouteMatch{ + { + Path: &gatev1.HTTPPathMatch{ + Type: ptr.To(gatev1.PathMatchExact), + Value: ptr.To("/foo/"), }, - { - Headers: []gatev1.HTTPHeaderMatch{ - { - Type: ptr.To(gatev1.HeaderMatchExact), - Name: "my-header", - Value: "foo", - }, + }, + { + Headers: []gatev1.HTTPHeaderMatch{ + { + Type: ptr.To(gatev1.HeaderMatchExact), + Name: "my-header", + Value: "foo", }, }, }, }, - expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`))", + expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || PathPrefix(`/`) && Header(`my-header`,`foo`))", + expectedPriority: 99987, }, } @@ -274,8 +272,9 @@ func Test_routerRule(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - rule := routerRule(test.routeRule, test.hostRule) + rule, priority := buildRouterRule(test.hostnames, test.routeMatches) assert.Equal(t, test.expectedRule, rule) + assert.Equal(t, test.expectedPriority, priority) }) } } diff --git a/pkg/provider/kubernetes/gateway/kubernetes_test.go b/pkg/provider/kubernetes/gateway/kubernetes_test.go index 033f19420..0a61618e1 100644 --- a/pkg/provider/kubernetes/gateway/kubernetes_test.go +++ b/pkg/provider/kubernetes/gateway/kubernetes_test.go @@ -198,16 +198,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -566,16 +567,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -626,10 +628,11 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, Service: "api@internal", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, @@ -659,17 +662,18 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -729,16 +733,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-66e726cd8903b49727ae": { + "default-http-app-1-my-gateway-web-da59521d735cff97495a": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-66e726cd8903b49727ae-wrr", - Rule: "(Host(`foo.com`) || Host(`bar.com`)) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-da59521d735cff97495a-wrr", + Rule: "(Host(`foo.com`) || Host(`bar.com`))", + Priority: 7, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-66e726cd8903b49727ae-wrr": { + "default-http-app-1-my-gateway-web-da59521d735cff97495a-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -789,16 +794,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-baa117c0219e3878749f": { + "default-http-app-1-my-gateway-web-2550b6c946893e8b737a": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-baa117c0219e3878749f-wrr", - Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.com$`)) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-2550b6c946893e8b737a-wrr", + Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.com$`))", + Priority: 9, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-baa117c0219e3878749f-wrr": { + "default-http-app-1-my-gateway-web-2550b6c946893e8b737a-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -849,16 +855,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-45eba2eaf40ac792e036": { + "default-http-app-1-my-gateway-web-0cd7265d0030f02bee3d": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-45eba2eaf40ac792e036-wrr", - Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.foo\\.com$`)) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-0cd7265d0030f02bee3d-wrr", + Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.foo\\.com$`))", + Priority: 9, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-45eba2eaf40ac792e036-wrr": { + "default-http-app-1-my-gateway-web-0cd7265d0030f02bee3d-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -909,22 +916,24 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Rule: "Host(`foo.com`) && Path(`/bar`)", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", }, - "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a": { + "default-http-app-1-my-gateway-web-f37ede0f5aa6cc3e3a16": { EntryPoints: []string{"web"}, - Rule: "Host(`foo.com`) && Path(`/bir`)", + Rule: "Host(`foo.com`) && (Path(`/bir`))", + Priority: 99997, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr", + Service: "default-http-app-1-my-gateway-web-f37ede0f5aa6cc3e3a16-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -934,7 +943,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr": { + "default-http-app-1-my-gateway-web-f37ede0f5aa6cc3e3a16-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1001,16 +1010,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Rule: "Host(`foo.com`) && Path(`/bar`)", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1086,23 +1096,25 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-http-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-http-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, - "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-https-websecure-af4b9876d1fe36359e27": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-https-websecure-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-http-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1112,7 +1124,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-https-websecure-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1177,23 +1189,25 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, - "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27": { EntryPoints: []string{"websecure"}, - Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1203,7 +1217,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-websecure-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1263,28 +1277,31 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-6cf37fa71907768d925c": { + "default-http-app-1-my-gateway-web-1f099b05db72cebb53a5": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-6cf37fa71907768d925c-wrr", - Rule: "Host(`foo.com`) && (Path(`/bar`) || PathPrefix(`/bar/`)) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`)", + Service: "default-http-app-1-my-gateway-web-1f099b05db72cebb53a5-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`) && Header(`my-header`,`bar`))", + Priority: 100097, RuleSyntax: "v3", }, - "default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276": { + "default-http-app-1-my-gateway-web-4863cbd61ecd5b4b0739": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`) && Header(`my-header`,`bar`)", + Service: "default-http-app-1-my-gateway-web-4863cbd61ecd5b4b0739-wrr", + Rule: "Host(`foo.com`) && (PathRegexp(`^/buzz/[0-9]+$`))", + Priority: 2397, RuleSyntax: "v3", }, - "default-http-app-1-my-gateway-web-d23f7039bc8036fb918c": { + "default-http-app-1-my-gateway-web-374af7817bd7c32eba26": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-d23f7039bc8036fb918c-wrr", - Rule: "Host(`foo.com`) && PathRegexp(`^/buzz/[0-9]+$`)", + Service: "default-http-app-1-my-gateway-web-374af7817bd7c32eba26-wrr", + Rule: "Host(`foo.com`) && ((Path(`/bar`) || PathPrefix(`/bar/`)) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`))", + Priority: 10597, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-6cf37fa71907768d925c-wrr": { + "default-http-app-1-my-gateway-web-1f099b05db72cebb53a5-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1294,7 +1311,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-aaba0f24fd26e1ca2276-wrr": { + "default-http-app-1-my-gateway-web-4863cbd61ecd5b4b0739-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1304,7 +1321,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "default-http-app-1-my-gateway-web-d23f7039bc8036fb918c-wrr": { + "default-http-app-1-my-gateway-web-374af7817bd7c32eba26-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1355,16 +1372,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-default-my-gateway-web-efde1997778109a1f6eb": { + "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr", - Rule: "Host(`foo.com`) && Path(`/foo`)", + Service: "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485-wrr", + Rule: "Host(`foo.com`) && (Path(`/foo`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr": { + "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1415,22 +1433,24 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-default-my-gateway-web-efde1997778109a1f6eb": { + "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485": { EntryPoints: []string{"web"}, - Service: "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr", - Rule: "Host(`foo.com`) && Path(`/foo`)", + Service: "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485-wrr", + Rule: "Host(`foo.com`) && (Path(`/foo`))", + Priority: 99997, RuleSyntax: "v3", }, - "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597": { + "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr", - Rule: "Host(`bar.com`) && Path(`/bar`)", + Service: "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a-wrr", + Rule: "Host(`bar.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-default-my-gateway-web-efde1997778109a1f6eb-wrr": { + "default-http-app-default-my-gateway-web-a0df3dbe37431caa4485-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1440,7 +1460,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, }, - "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr": { + "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1507,16 +1527,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597": { + "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a": { EntryPoints: []string{"web"}, - Service: "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr", - Rule: "Host(`bar.com`) && Path(`/bar`)", + Service: "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a-wrr", + Rule: "Host(`bar.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "bar-http-app-bar-my-gateway-web-66f5c78d03d948e36597-wrr": { + "bar-http-app-bar-my-gateway-web-c7f946bee1e5b1751d6a-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1567,16 +1588,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr", - Rule: "Host(`example.org`) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr", + Rule: "Host(`example.org`)", + Priority: 11, RuleSyntax: "v3", - Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0"}, + Middlewares: []string{"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestheadermodifier-0"}, }, }, Middlewares: map[string]*dynamic.Middleware{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestheadermodifier-0": { RequestHeaderModifier: &dynamic.RequestHeaderModifier{ Set: map[string]string{"X-Foo": "Bar"}, Add: map[string]string{"X-Bar": "Foo"}, @@ -1585,7 +1607,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1636,16 +1658,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr", - Rule: "Host(`example.org`) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr", + Rule: "Host(`example.org`)", + Priority: 11, RuleSyntax: "v3", - Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"}, + Middlewares: []string{"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0"}, }, }, Middlewares: map[string]*dynamic.Middleware{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0": { RedirectRegex: &dynamic.RedirectRegex{ Regex: "^[a-z]+:\\/\\/(?P.+@)?(?P\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P:\\d+)?\\/(?P.*)", Replacement: "https://${userinfo}${hostname}${port}/${path}", @@ -1654,7 +1677,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1705,16 +1728,17 @@ func TestLoadHTTPRoutes(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr", - Rule: "Host(`example.org`) && PathPrefix(`/`)", + Service: "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr", + Rule: "Host(`example.org`)", + Priority: 11, RuleSyntax: "v3", - Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0"}, + Middlewares: []string{"default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0"}, }, }, Middlewares: map[string]*dynamic.Middleware{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestredirect-0": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-requestredirect-0": { RedirectRegex: &dynamic.RedirectRegex{ Regex: "^[a-z]+:\\/\\/(?P.+@)?(?P\\[[\\w:\\.]+\\]|[\\w\\._-]+)(?P:\\d+)?\\/(?P.*)", Replacement: "http://${userinfo}example.com:443/${path}", @@ -1722,7 +1746,7 @@ func TestLoadHTTPRoutes(t *testing.T) { }, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr": { + "default-http-app-1-my-gateway-web-fa136e10345bd0e7248d-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1822,16 +1846,17 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1871,16 +1896,17 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1922,16 +1948,17 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -1972,16 +1999,17 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2023,16 +2051,17 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2136,17 +2165,18 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", Middlewares: []string{"default-my-middleware"}, }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2201,10 +2231,11 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", Middlewares: []string{"default-my-middleware"}, }, @@ -2213,7 +2244,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { "default-my-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, }, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2263,16 +2294,17 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -2312,16 +2344,17 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) { }, HTTP: &dynamic.HTTPConfiguration{ Routers: map[string]*dynamic.Router{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27": { EntryPoints: []string{"web"}, - Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr", - Rule: "Host(`foo.com`) && Path(`/bar`)", + Service: "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr", + Rule: "Host(`foo.com`) && (Path(`/bar`))", + Priority: 99997, RuleSyntax: "v3", }, }, Middlewares: map[string]*dynamic.Middleware{}, Services: map[string]*dynamic.Service{ - "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": { + "default-http-app-1-my-gateway-web-af4b9876d1fe36359e27-wrr": { Weighted: &dynamic.WeightedRoundRobin{ Services: []dynamic.WRRService{ { @@ -4489,12 +4522,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "default-http-app-1-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "default-http-app-1-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "default-http-app-1-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, @@ -4674,12 +4709,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, @@ -4876,12 +4913,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, @@ -4889,12 +4928,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, @@ -5082,12 +5123,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "bar-http-app-bar-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "bar-http-app-bar-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, }, @@ -5219,12 +5262,14 @@ func TestLoadMixedRoutes(t *testing.T) { EntryPoints: []string{"web"}, Service: "default-http-app-default-my-gateway-web-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", }, "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd": { EntryPoints: []string{"websecure"}, Service: "default-http-app-default-my-gateway-websecure-a431b128267aabc954fd-wrr", Rule: "PathPrefix(`/`)", + Priority: 1, RuleSyntax: "v3", TLS: &dynamic.RouterTLSConfig{}, },