Skip to content

Commit f2a65d8

Browse files
authored
Add Support for Priority Configuration in HTTPRoute Resource (#734)
* Added unit tests * Added integration tests * Updated advanced configuration documentation * Correct priority queue
1 parent 4602593 commit f2a65d8

File tree

5 files changed

+596
-7
lines changed

5 files changed

+596
-7
lines changed

docs/guides/advanced-configurations.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,38 @@ However, the controller utilizes [IMDS](https://docs.aws.amazon.com/AWSEC2/lates
1616

1717
- **If your cluster cannot access to IMDS.** ensure to specify the[configuration variables](environment.md) when installing the controller.
1818

19+
### Rule Priority Configuration
20+
21+
You can manually assign priorities to rules using the custom annotation `application-networking.k8s.aws/rule-{index}-priority`. This annotation allows you to explicitly set the priority for specific rules in your route configurations.
22+
23+
For example, to set priorities for multiple rules in an HTTPRoute:
24+
25+
```yaml
26+
apiVersion: gateway.networking.k8s.io/v1beta1
27+
kind: HTTPRoute
28+
metadata:
29+
name: example-route
30+
annotations:
31+
application-networking.k8s.aws/rule-0-priority: "200" # First rule gets higher priority
32+
application-networking.k8s.aws/rule-1-priority: "100" # Second rule gets lower priority
33+
spec:
34+
rules:
35+
- matches: # This is rule[0]
36+
- path:
37+
type: PathPrefix
38+
value: /api/v2
39+
- matches: # This is rule[1]
40+
- path:
41+
type: PathPrefix
42+
value: /api
43+
```
44+
45+
The `{index}` in the annotation corresponds to the zero-based index of the rule in the rules array. In this example:
46+
- `rule-0-priority: "200"` applies to the first rule matching `/api/v2`
47+
- `rule-1-priority: "100"` applies to the second rule matching `/api`
48+
49+
Higher priority values indicate higher precedence, so requests to `/api/v2` will be matched by the first rule (priority 200) before the second rule (priority 100) is considered.
50+
1951
### IPv6 support
2052

2153
IPv6 address type is automatically used for your services and pods if

pkg/gateway/model_build_rule.go

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"strconv"
78

89
apierrors "k8s.io/apimachinery/pkg/api/errors"
910
"k8s.io/apimachinery/pkg/types"
1011

1112
anv1alpha1 "github.com/aws/aws-application-networking-k8s/pkg/apis/applicationnetworking/v1alpha1"
1213
"github.com/aws/aws-application-networking-k8s/pkg/model/core"
14+
"github.com/aws/aws-application-networking-k8s/pkg/utils"
1315

1416
"github.com/aws/aws-sdk-go/aws"
1517

@@ -32,10 +34,59 @@ func (t *latticeServiceModelBuildTask) buildRules(ctx context.Context, stackList
3234
// note we only build rules for non-deleted routes
3335
t.log.Debugf(ctx, "Processing %d rules", len(t.route.Spec().Rules()))
3436

37+
// Track rules with and without priority
38+
rulesWithoutPriority := make([]core.RouteRule, 0)
39+
priorityQueue := make(utils.PriorityQueue, 0)
40+
41+
// First pass: build all rules and add them to priority queue
3542
for i, rule := range t.route.Spec().Rules() {
43+
// Default priority is index + 1
44+
priority := int64(i + 1)
45+
46+
// Check for priority annotation in format: application-networking.k8s.aws/rule-{index}-priority
47+
if priorityStr, ok := t.route.K8sObject().GetAnnotations()[fmt.Sprintf("application-networking.k8s.aws/rule-%d-priority", i)]; ok {
48+
if p, err := strconv.ParseInt(priorityStr, 10, 64); err == nil {
49+
priority = p
50+
t.log.Debugf(ctx, "Using priority %d from annotation for rule %d", priority, i)
51+
} else {
52+
t.log.Warnf(ctx, "Invalid priority value in annotation for rule %d: %s", i, priorityStr)
53+
}
54+
55+
priorityQueue.Push(&utils.Item{
56+
Value: rule,
57+
Priority: int32(priority),
58+
})
59+
60+
} else {
61+
rulesWithoutPriority = append(rulesWithoutPriority, rule)
62+
}
63+
}
64+
65+
// Assign rules without a manually assigned priority a priority in sequential order following the greatest
66+
// manually assigned priority
67+
for _, ruleSpec := range rulesWithoutPriority {
68+
// No manually assigned priorities
69+
topItem, err := priorityQueue.Peek()
70+
if err == nil {
71+
t.log.Debugf(ctx, "Setting default rule priority set to: %d", topItem.Priority+1)
72+
priorityQueue.Push(&utils.Item{
73+
Value: ruleSpec,
74+
Priority: topItem.Priority + 1,
75+
})
76+
} else {
77+
t.log.Debugf(ctx, "Setting default rule priority set to: %d", 1)
78+
priorityQueue.Push(&utils.Item{
79+
Value: ruleSpec,
80+
Priority: 1,
81+
})
82+
}
83+
}
84+
85+
for _, item := range priorityQueue {
86+
rule := item.Value.(core.RouteRule)
3687
ruleSpec := model.RuleSpec{
3788
StackListenerId: stackListenerId,
38-
Priority: int64(i + 1),
89+
Priority: int64(item.Priority),
3990
}
4091

4192
if len(rule.Matches()) > 1 {
@@ -62,14 +113,12 @@ func (t *latticeServiceModelBuildTask) buildRules(ctx context.Context, stackList
62113
return err
63114
}
64115
} else {
65-
66116
// Match every traffic on no matches
67117
ruleSpec.PathMatchValue = "/"
68118
ruleSpec.PathMatchPrefix = true
69119
if _, ok := rule.(*core.GRPCRouteRule); ok {
70120
ruleSpec.Method = string(gwv1.HTTPMethodPost)
71121
}
72-
73122
}
74123

75124
ruleTgList, err := t.getTargetGroupsForRuleAction(ctx, rule)

0 commit comments

Comments
 (0)