feat: add more precedence rules for route matching (#214)

Signed-off-by: charlie <qianglin98@qq.com>
This commit is contained in:
Qianglin Li
2023-03-08 10:29:32 +08:00
committed by GitHub
parent 7f6b157a19
commit ff560b8d25
15 changed files with 814 additions and 63 deletions

View File

@@ -38,6 +38,11 @@ type WrapperConfig struct {
AnnotationsConfig *annotations.Ingress
}
type WrapperConfigWithRuleKey struct {
Config *config.Config
RuleKey string
}
type WrapperGateway struct {
Gateway *networking.Gateway
WrapperConfig *WrapperConfig
@@ -70,6 +75,8 @@ type WrapperHTTPRoute struct {
OriginPathType PathType
WeightTotal int32
IsDefaultBackend bool
RuleKey string
RuleHash uint32
}
func (w *WrapperHTTPRoute) Meta() string {

View File

@@ -149,7 +149,8 @@ type ConvertOptions struct {
IngressDomainCache *IngressDomainCache
HostAndPath2Ingress map[string]*config.Config
// the host, path, headers, params of rule => ingress
Route2Ingress map[uint32]*WrapperConfigWithRuleKey
// Record valid/invalid routes from ingress
IngressRouteCache *IngressRouteCache

View File

@@ -175,6 +175,9 @@ func SortHTTPRoutes(routes []*WrapperHTTPRoute) {
return false
}
// default backend,user specified root path => path type => path length =>
// methods => header => query param
// refer https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRouteSpec
sort.SliceStable(routes, func(i, j int) bool {
// Move default backend to end
if isDefaultBackend(routes[i]) {
@@ -193,7 +196,27 @@ func SortHTTPRoutes(routes []*WrapperHTTPRoute) {
}
if routes[i].OriginPathType == routes[j].OriginPathType {
return len(routes[i].OriginPath) > len(routes[j].OriginPath)
if in, jn := len(routes[i].OriginPath), len(routes[j].OriginPath); in != jn {
return in > jn
}
match1, match2 := routes[i].HTTPRoute.Match[0], routes[j].HTTPRoute.Match[0]
// methods
if in, jn := len(match1.Method.GetRegex()), len(match2.Method.GetRegex()); in != jn {
if in != 0 && jn != 0 {
return in < jn
}
return in != 0
}
// headers
if in, jn := len(match1.Headers), len(match2.Headers); in != jn {
return in > jn
}
// query params
if in, jn := len(match1.QueryParams), len(match2.QueryParams); in != jn {
return in > jn
}
return false
}
if routes[i].OriginPathType == Exact {

View File

@@ -416,3 +416,143 @@ func TestSortRoutes(t *testing.T) {
t.Fatal("should be test-3")
}
}
// TestSortHTTPRoutesWithMoreRules include headers, query params, methods
func TestSortHTTPRoutesWithMoreRules(t *testing.T) {
input := []struct {
order string
pathType PathType
path string
method *networking.StringMatch
header map[string]*networking.StringMatch
queryParam map[string]*networking.StringMatch
}{
{
order: "1",
pathType: Exact,
path: "/bar",
},
{
order: "2",
pathType: Prefix,
path: "/bar",
},
{
order: "3",
pathType: Prefix,
path: "/bar",
method: &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: "GET|PUT"},
},
},
{
order: "4",
pathType: Prefix,
path: "/bar",
method: &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
},
},
{
order: "5",
pathType: Prefix,
path: "/bar",
header: map[string]*networking.StringMatch{
"foo": {
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
},
},
},
{
order: "6",
pathType: Prefix,
path: "/bar",
header: map[string]*networking.StringMatch{
"foo": {
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
},
"bar": {
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
},
},
},
{
order: "7",
pathType: Prefix,
path: "/bar",
queryParam: map[string]*networking.StringMatch{
"foo": {
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
},
},
},
{
order: "8",
pathType: Prefix,
path: "/bar",
queryParam: map[string]*networking.StringMatch{
"foo": {
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
},
"bar": {
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
},
},
},
{
order: "9",
pathType: Prefix,
path: "/bar",
method: &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
},
queryParam: map[string]*networking.StringMatch{
"foo": {
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
},
},
},
{
order: "10",
pathType: Prefix,
path: "/bar",
method: &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
},
queryParam: map[string]*networking.StringMatch{
"bar": {
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
},
},
},
}
origin := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
expect := []string{"1", "9", "10", "4", "3", "6", "5", "8", "7", "2"}
var list []*WrapperHTTPRoute
for idx, val := range input {
list = append(list, &WrapperHTTPRoute{
OriginPath: val.path,
OriginPathType: val.pathType,
HTTPRoute: &networking.HTTPRoute{
Name: origin[idx],
Match: []*networking.HTTPMatchRequest{
{
Method: val.method,
Headers: val.header,
QueryParams: val.queryParam,
},
},
},
})
}
SortHTTPRoutes(list)
for idx, val := range list {
if val.HTTPRoute.Name != expect[idx] {
t.Fatalf("should be %s, but got %s", expect[idx], val.HTTPRoute.Name)
}
}
}