From 594528e6583ce066966bbaf9f8bd8277f12edfa6 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 22 Jan 2026 10:54:17 +0100 Subject: [PATCH 1/2] Effective plan policy behavior explained Signed-off-by: Eguzki Astiz Lezaun --- internal/controller/apiproduct_controller.go | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/internal/controller/apiproduct_controller.go b/internal/controller/apiproduct_controller.go index 10a662e..847fbcd 100644 --- a/internal/controller/apiproduct_controller.go +++ b/internal/controller/apiproduct_controller.go @@ -340,6 +340,27 @@ func (r *APIProductReconciler) openAPISpecReadyCondition(openAPISpec *devportalv return &condition } +// findPlanPolicyForAPIProduct discovers the effective PlanPolicy for an APIProduct by searching +// in order of specificity: HTTPRoute-level first, then Gateway-level. +// +// Lookup hierarchy: +// 1. PlanPolicy targeting the HTTPRoute directly (most specific) +// 2. PlanPolicy targeting a Gateway that the HTTPRoute references (less specific) +// +// Multiple PlanPolicies scenario: +// When both HTTPRoute-level and Gateway-level PlanPolicies exist: +// - PlanPolicy A (targeting Gateway) creates → RateLimitPolicy A (targeting Gateway) +// - PlanPolicy B (targeting HTTPRoute) creates → RateLimitPolicy B (targeting HTTPRoute) +// - RateLimitPolicy B will atomically override RateLimitPolicy A for that specific HTTPRoute +// +// The effective policy is NOT a merge of both PlanPolicies. Instead, the most specific +// RateLimitPolicy wins via atomic override because: +// - Both use atomic merge strategy (default) +// - More specific policies (HTTPRoute-level) take precedence over less specific ones (Gateway-level) +// - The atomic strategy means the entire policy is replaced, not merged rule-by-rule +// +// This function returns only the most specific PlanPolicy found, which will be the one +// that determines the effective rate limiting behavior for the APIProduct. func (r *APIProductReconciler) findPlanPolicyForAPIProduct(ctx context.Context, apiProductObj *devportalv1alpha1.APIProduct) (*planpolicyv1alpha1.PlanPolicy, error) { route := &gwapiv1.HTTPRoute{} rKey := client.ObjectKey{ // Its deployment is built after the same name and namespace From ae6ce86484615f3bc02621f21f39faa8bf8c1d82 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Thu, 22 Jan 2026 10:58:03 +0100 Subject: [PATCH 2/2] fix lint issue Signed-off-by: Eguzki Astiz Lezaun --- internal/controller/apiproduct_controller.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/controller/apiproduct_controller.go b/internal/controller/apiproduct_controller.go index 847fbcd..e02ef06 100644 --- a/internal/controller/apiproduct_controller.go +++ b/internal/controller/apiproduct_controller.go @@ -349,15 +349,15 @@ func (r *APIProductReconciler) openAPISpecReadyCondition(openAPISpec *devportalv // // Multiple PlanPolicies scenario: // When both HTTPRoute-level and Gateway-level PlanPolicies exist: -// - PlanPolicy A (targeting Gateway) creates → RateLimitPolicy A (targeting Gateway) -// - PlanPolicy B (targeting HTTPRoute) creates → RateLimitPolicy B (targeting HTTPRoute) -// - RateLimitPolicy B will atomically override RateLimitPolicy A for that specific HTTPRoute +// - PlanPolicy A (targeting Gateway) creates → RateLimitPolicy A (targeting Gateway) +// - PlanPolicy B (targeting HTTPRoute) creates → RateLimitPolicy B (targeting HTTPRoute) +// - RateLimitPolicy B will atomically override RateLimitPolicy A for that specific HTTPRoute // // The effective policy is NOT a merge of both PlanPolicies. Instead, the most specific // RateLimitPolicy wins via atomic override because: -// - Both use atomic merge strategy (default) -// - More specific policies (HTTPRoute-level) take precedence over less specific ones (Gateway-level) -// - The atomic strategy means the entire policy is replaced, not merged rule-by-rule +// - Both use atomic merge strategy (default) +// - More specific policies (HTTPRoute-level) take precedence over less specific ones (Gateway-level) +// - The atomic strategy means the entire policy is replaced, not merged rule-by-rule // // This function returns only the most specific PlanPolicy found, which will be the one // that determines the effective rate limiting behavior for the APIProduct.