Skip to content

Commit ebe1a05

Browse files
authored
Sort ingress rules by path length and pathType (#2409)
* sort ingress rules by path length * add unit test * sort paths instead of sorting rules directly * update sorting strategy
1 parent b5c8905 commit ebe1a05

File tree

2 files changed

+393
-1
lines changed

2 files changed

+393
-1
lines changed

pkg/ingress/model_build_listener_rules.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ingress
33
import (
44
"context"
55
"fmt"
6+
"sort"
67
"strings"
78

89
"github.com/pkg/errors"
@@ -24,7 +25,11 @@ func (t *defaultModelBuildTask) buildListenerRules(ctx context.Context, lsARN co
2425
if rule.HTTP == nil {
2526
continue
2627
}
27-
for _, path := range rule.HTTP.Paths {
28+
paths, err := t.sortIngressPaths(rule.HTTP.Paths)
29+
if err != nil {
30+
return err
31+
}
32+
for _, path := range paths {
2833
enhancedBackend, err := t.enhancedBackendBuilder.Build(ctx, ing.Ing, path.Backend,
2934
WithLoadBackendServices(true, t.backendServices),
3035
WithLoadAuthConfig(true))
@@ -72,6 +77,48 @@ func (t *defaultModelBuildTask) buildListenerRules(ctx context.Context, lsARN co
7277
return nil
7378
}
7479

80+
// sortIngressPaths will sort the paths following the strategy:
81+
// all exact match paths come first, no need to sort since exact match has to be unique
82+
// followed by prefix paths, sort by lengths - longer paths get precedence
83+
// followed by ImplementationSpecific paths or paths with no pathType specified, keep the original order
84+
func (t *defaultModelBuildTask) sortIngressPaths(paths []networking.HTTPIngressPath) ([]networking.HTTPIngressPath, error) {
85+
exactPaths, prefixPaths, implementationSpecificPaths, err := t.classifyIngressPathsByType(paths)
86+
if err != nil {
87+
return nil, err
88+
}
89+
sortedPaths := exactPaths
90+
sort.SliceStable(prefixPaths, func(i, j int) bool {
91+
return len(prefixPaths[i].Path) > len(prefixPaths[j].Path)
92+
})
93+
sortedPaths = append(sortedPaths, prefixPaths...)
94+
sortedPaths = append(sortedPaths, implementationSpecificPaths...)
95+
return sortedPaths, nil
96+
}
97+
98+
// classifyIngressPathsByType will classify the paths by type Exact, Prefix and ImplementationSpecific
99+
func (t *defaultModelBuildTask) classifyIngressPathsByType(paths []networking.HTTPIngressPath) ([]networking.HTTPIngressPath, []networking.HTTPIngressPath, []networking.HTTPIngressPath, error) {
100+
var exactPaths []networking.HTTPIngressPath
101+
var prefixPaths []networking.HTTPIngressPath
102+
var implementationSpecificPaths []networking.HTTPIngressPath
103+
for _, path := range paths {
104+
if path.PathType != nil {
105+
switch *path.PathType {
106+
case networking.PathTypeExact:
107+
exactPaths = append(exactPaths, path)
108+
case networking.PathTypePrefix:
109+
prefixPaths = append(prefixPaths, path)
110+
case networking.PathTypeImplementationSpecific:
111+
implementationSpecificPaths = append(implementationSpecificPaths, path)
112+
default:
113+
return nil, nil, nil, errors.Errorf("unknown pathType for path %s", path.Path)
114+
}
115+
} else {
116+
implementationSpecificPaths = append(implementationSpecificPaths, path)
117+
}
118+
}
119+
return exactPaths, prefixPaths, implementationSpecificPaths, nil
120+
}
121+
75122
func (t *defaultModelBuildTask) buildRuleConditions(ctx context.Context, rule networking.IngressRule,
76123
path networking.HTTPIngressPath, backend EnhancedBackend) ([]elbv2model.RuleCondition, error) {
77124
var hosts []string

0 commit comments

Comments
 (0)