Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
29cbc48
moved shared under rules
ryanhristovski May 6, 2025
e9816e6
Fix some logic
ryanhristovski May 7, 2025
81a703e
fix rule logic
ryanhristovski May 7, 2025
0f00ae5
fix some tests
ryanhristovski May 7, 2025
56c4ded
fix tests
ryanhristovski May 7, 2025
75f4b7a
Fix descriptor hierarchy
ryanhristovski May 7, 2025
71aacb1
comments
ryanhristovski May 7, 2025
25709d3
fmt
ryanhristovski May 7, 2025
4fb75bd
Merge remote-tracking branch 'origin/main' into merge-shared-ratelimits
ryanhristovski May 7, 2025
d5b9272
Merge remote-tracking branch 'origin/main' into merge-shared-ratelimits
ryanhristovski May 8, 2025
1799675
fmt
ryanhristovski May 8, 2025
36e8dc8
fmt
ryanhristovski May 8, 2025
0795353
Fix shared ratelimit merging and btp rl merging
ryanhristovski May 8, 2025
34d6d2c
extensions.md update
ryanhristovski May 9, 2025
a279e35
Cleanup code and fix tests
ryanhristovski May 9, 2025
cded06a
formatting and remove unused functions
ryanhristovski May 9, 2025
1fc2bd7
update BuildRateLimitServiceConfig to be easier to read
ryanhristovski May 9, 2025
68e7fe8
Merge branch 'main' into merge-shared-ratelimits
ryanhristovski May 9, 2025
486ccfc
linting & gen
ryanhristovski May 9, 2025
4f47672
Merge branch 'main' into merge-shared-ratelimits
ryanhristovski May 9, 2025
12daace
Fix test
ryanhristovski May 9, 2025
9dd386d
Merge branch 'main' into merge-shared-ratelimits
ryanhristovski May 9, 2025
92aab03
remove default false
ryanhristovski May 9, 2025
c89cfaa
Write e2e test + resolve pr suggestions
ryanhristovski May 9, 2025
b536a4c
fix test
ryanhristovski May 9, 2025
a594c36
lint
ryanhristovski May 9, 2025
60e2558
Merge remote-tracking branch 'origin/main' into merge-shared-ratelimits
ryanhristovski May 12, 2025
04c1f92
Fix merging logic for global rate limits
ryanhristovski May 12, 2025
922bb4e
Fix local rate limit merging, add tests for multiple shared
ryanhristovski May 12, 2025
951f28a
linting
ryanhristovski May 12, 2025
843062e
lint
ryanhristovski May 12, 2025
2f768b8
linting
ryanhristovski May 12, 2025
3a3d68c
linting and fix tests
ryanhristovski May 12, 2025
9ecbf2a
update testdata out
ryanhristovski May 12, 2025
27884b6
Fix hard coded e2e tests
ryanhristovski May 12, 2025
4f9109e
Try fixing e2e test
ryanhristovski May 12, 2025
397b7c8
cleanup xds ratelimit, fix e2es
ryanhristovski May 12, 2025
271ad45
fix shared test
ryanhristovski May 12, 2025
10a5369
Merge branch 'main' into merge-shared-ratelimits
arkodg May 13, 2025
222fb13
Merge branch 'main' into merge-shared-ratelimits
zhaohuabing May 13, 2025
344fa01
Fix adddescriptor function
ryanhristovski May 13, 2025
af26dd3
add readiness checks to e2e test
ryanhristovski May 13, 2025
f438546
fix tests, update internal merge func
ryanhristovski May 13, 2025
f7c35f5
Merge branch 'main' into merge-shared-ratelimits
ryanhristovski May 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 8 additions & 21 deletions api/v1alpha1/ratelimit_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,8 @@ type GlobalRateLimit struct {
// matches two rules, one rate limited and one not, the final decision will be
// to rate limit the request.
//
// +patchMergeKey:"name"
// +patchStrategy:"merge"
// +kubebuilder:validation:MaxItems=64
Rules []RateLimitRule `json:"rules" patchMergeKey:"name" patchStrategy:"merge"`

// Shared determines whether the rate limit rules apply across all the policy targets.
// If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
// Default: false.
//
// +optional
// +notImplementedHide
// +kubebuilder:default=false
Shared *bool `json:"shared,omitempty"`
Rules []RateLimitRule `json:"rules"`
}

// LocalRateLimit defines local rate limit configuration.
Expand All @@ -71,23 +60,15 @@ type LocalRateLimit struct {
// matches two rules, one with 10rps and one with 20rps, the final limit will
// be based on the rule with 10rps.
//
// +patchMergeKey:"name"
// +patchStrategy:"merge"
//
// +optional
// +kubebuilder:validation:MaxItems=16
// +kubebuilder:validation:XValidation:rule="self.all(foo, !has(foo.cost) || !has(foo.cost.response))", message="response cost is not supported for Local Rate Limits"
Rules []RateLimitRule `json:"rules" patchMergeKey:"name" patchStrategy:"merge"`
Rules []RateLimitRule `json:"rules"`
}

// RateLimitRule defines the semantics for matching attributes
// from the incoming requests, and setting limits for them.
type RateLimitRule struct {
// Name is the name of the rule. This is used to identify the rule
// in the Envoy configuration and as a unique identifier for merging.
//
// +optional
Name string `json:"name,omitempty"`
// ClientSelectors holds the list of select conditions to select
// specific clients using attributes from the traffic flow.
// All individual select conditions must hold True for this rule
Expand Down Expand Up @@ -118,6 +99,12 @@ type RateLimitRule struct {
//
// +optional
Cost *RateLimitCost `json:"cost,omitempty"`
// Shared determines whether this rate limit rule applies across all the policy targets.
// If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
// Default: false.
//
// +optional
Shared *bool `json:"shared,omitempty"`
}

type RateLimitCost struct {
Expand Down
10 changes: 5 additions & 5 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -948,23 +948,17 @@ spec:
- requests
- unit
type: object
name:
shared:
description: |-
Name is the name of the rule. This is used to identify the rule
in the Envoy configuration and as a unique identifier for merging.
type: string
Shared determines whether this rate limit rule applies across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- limit
type: object
maxItems: 64
type: array
shared:
default: false
description: |-
Shared determines whether the rate limit rules apply across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- rules
type: object
Expand Down Expand Up @@ -1203,11 +1197,12 @@ spec:
- requests
- unit
type: object
name:
shared:
description: |-
Name is the name of the rule. This is used to identify the rule
in the Envoy configuration and as a unique identifier for merging.
type: string
Shared determines whether this rate limit rule applies across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- limit
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -947,23 +947,17 @@ spec:
- requests
- unit
type: object
name:
shared:
description: |-
Name is the name of the rule. This is used to identify the rule
in the Envoy configuration and as a unique identifier for merging.
type: string
Shared determines whether this rate limit rule applies across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- limit
type: object
maxItems: 64
type: array
shared:
default: false
description: |-
Shared determines whether the rate limit rules apply across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- rules
type: object
Expand Down Expand Up @@ -1202,11 +1196,12 @@ spec:
- requests
- unit
type: object
name:
shared:
description: |-
Name is the name of the rule. This is used to identify the rule
in the Envoy configuration and as a unique identifier for merging.
type: string
Shared determines whether this rate limit rule applies across all the policy targets.
If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
Default: false.
type: boolean
required:
- limit
type: object
Expand Down
34 changes: 28 additions & 6 deletions internal/gatewayapi/backendtrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,33 @@
if err != nil {
return fmt.Errorf("error merging policies: %w", err)
}

// Build traffic features from the merged policy
tf, errs := t.buildTrafficFeatures(mergedPolicy, resources)
if tf == nil {
// should not happen
return nil
}

// Apply IR to relevant gateway routes
// Since GlobalRateLimit merge relies on IR auto-generated key: (<policy-ns>/<policy-name>/rule/<rule-index>)
// We can't simply merge the BTP's using utils.Merge() we need to specifically merge the GlobalRateLimit.Rules using IR fields.
// Since ir.TrafficFeatures is not a built-in Kubernetes API object with defined merging strategies and it does not support a deep merge (for lists/maps).
if policy.Spec.RateLimit != nil && gwPolicy.Spec.RateLimit != nil {
tfGW, _ := t.buildTrafficFeatures(gwPolicy, resources)
tfRoute, _ := t.buildTrafficFeatures(policy, resources)

if tfGW != nil && tfRoute != nil &&
tfGW.RateLimit != nil && tfRoute.RateLimit != nil {

mergedRL, err := utils.MergeRL(tfGW.RateLimit, tfRoute.RateLimit, *policy.Spec.MergeType)
if err != nil {
return fmt.Errorf("error merging rate limits: %w", err)
}

Check warning on line 453 in internal/gatewayapi/backendtrafficpolicy.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/backendtrafficpolicy.go#L452-L453

Added lines #L452 - L453 were not covered by tests
// Replace the rate limit in the merged features if successful
tf.RateLimit = mergedRL
}
}

x, ok := xdsIR[t.IRKey(gatewayNN)]
if !ok {
// should not happen.
Expand Down Expand Up @@ -489,7 +509,6 @@
}

r.Traffic = tf.DeepCopy()
r.Traffic.Name = irTrafficName(policy)

if localTo, err := buildClusterSettingsTimeout(policy.Spec.ClusterSettings); err == nil {
r.Traffic.Timeout = localTo
Expand Down Expand Up @@ -695,7 +714,6 @@
}

r.Traffic = tf.DeepCopy()
r.Traffic.Name = irTrafficName(policy)

// Update the Host field in HealthCheck, now that we have access to the Route Hostname.
r.Traffic.HealthCheck.SetHTTPHostIfAbsent(r.Hostname)
Expand Down Expand Up @@ -769,7 +787,7 @@
var err error
var irRule *ir.RateLimitRule
irRules := make([]*ir.RateLimitRule, 0)
for _, rule := range local.Rules {
for i, rule := range local.Rules {
// We don't process the rule without clientSelectors here because it's
// previously used as the default route-level limit.
if len(rule.ClientSelectors) == 0 {
Expand All @@ -780,6 +798,8 @@
if err != nil {
return nil, err
}
// Set the Name field as <policy-ns>/<policy-name>/rule/<rule-index>
irRule.Name = irRuleName(policy.Namespace, policy.Name, i)
irRules = append(irRules, irRule)
}

Expand All @@ -804,8 +824,7 @@
global := policy.Spec.RateLimit.Global
rateLimit := &ir.RateLimit{
Global: &ir.GlobalRateLimit{
Rules: make([]*ir.RateLimitRule, len(global.Rules)),
Shared: global.Shared,
Rules: make([]*ir.RateLimitRule, len(global.Rules)),
},
}

Expand All @@ -816,6 +835,8 @@
if err != nil {
return nil, err
}
// Set the Name field as <policy-ns>/<policy-name>/rule/<rule-index>
irRules[i].Name = irRuleName(policy.Namespace, policy.Name, i)
}

return rateLimit, nil
Expand All @@ -828,6 +849,7 @@
Unit: ir.RateLimitUnit(rule.Limit.Unit),
},
HeaderMatches: make([]*ir.StringMatch, 0),
Shared: rule.Shared,
}

for _, match := range rule.ClientSelectors {
Expand Down
9 changes: 4 additions & 5 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,10 @@ func irDestinationSettingName(destName string, backendIdx int) string {
return fmt.Sprintf("%s/backend/%d", destName, backendIdx)
}

func irRuleName(policyNamespace, policyName string, ruleIndex int) string {
return fmt.Sprintf("%s/%s/rule/%d", policyNamespace, policyName, ruleIndex)
}

// irTLSConfigs produces a defaulted IR TLSConfig
func irTLSConfigs(tlsSecrets ...*corev1.Secret) *ir.TLSConfig {
if len(tlsSecrets) == 0 {
Expand Down Expand Up @@ -450,11 +454,6 @@ func irTLSCACertName(namespace, name string) string {
return fmt.Sprintf("%s/%s/%s", namespace, name, caCertKey)
}

// Helper function to format the policy name and namespace
func irTrafficName(policy *egv1a1.BackendTrafficPolicy) string {
return fmt.Sprintf("%s/%s", policy.Namespace, policy.Name)
}

func IsMergeGatewaysEnabled(resources *resource.Resources) bool {
return resources.EnvoyProxyForGatewayClass != nil && resources.EnvoyProxyForGatewayClass.Spec.MergeGateways != nil && *resources.EnvoyProxyForGatewayClass.Spec.MergeGateways
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ xdsIR:
namespace: default
name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
traffic:
name: envoy-gateway/policy-for-gateway
timeout:
http:
connectionIdleTimeout: 16s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ xdsIR:
namespace: default
name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
traffic:
name: envoy-gateway/policy-for-gateway
timeout:
http:
connectionIdleTimeout: 16s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ xdsIR:
namespace: default
name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
traffic:
name: envoy-gateway/policy-for-gateway
timeout:
http:
connectionIdleTimeout: 16s
Expand Down Expand Up @@ -340,7 +339,6 @@ xdsIR:
traffic:
backendConnection:
bufferLimit: 100000000
name: default/policy-for-route
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ xdsIR:
compression:
- type: Brotli
- type: Gzip
name: default/policy-for-route
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,6 @@ xdsIR:
dnsRefreshRate: 5s
lookupFamily: IPv6
respectDnsTtl: false
name: default/backend-traffic-policy
- destination:
name: grpcroute/default/grpcroute-1/rule/0
settings:
Expand Down Expand Up @@ -495,7 +494,6 @@ xdsIR:
dnsRefreshRate: 5s
lookupFamily: IPv6
respectDnsTtl: false
name: default/backend-traffic-policy
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ xdsIR:
traffic:
httpUpgrade:
- spdy/3.1
name: default/policy-for-route
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ xdsIR:
httpUpgrade:
- websocket
- spdy/3.1
name: default/policy-for-route
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ xdsIR:
loadBalancer:
consistentHash:
sourceIP: true
name: default/policy-for-route-1
- destination:
name: httproute/default/httproute-2/rule/0
settings:
Expand All @@ -338,7 +337,6 @@ xdsIR:
traffic:
loadBalancer:
random: {}
name: envoy-gateway/policy-for-gateway-1
timeout:
http:
connectionIdleTimeout: 21s
Expand Down Expand Up @@ -366,8 +364,7 @@ xdsIR:
distinct: false
name: ""
prefix: /baz
traffic:
name: default/policy-for-route-3
traffic: {}
readyListener:
address: 0.0.0.0
ipFamily: IPv4
Expand Down
Loading