From 1ea45e548461fca41f4a7d3b02a02941bf8bb750 Mon Sep 17 00:00:00 2001 From: TomerJLevy Date: Thu, 28 Aug 2025 20:48:50 +0200 Subject: [PATCH 1/8] fix: handle context errors as transient errors (#6850) * handle context errors as transient errors Signed-off-by: TomerJLevy * add test cases Signed-off-by: TomerJLevy * no need the new line Signed-off-by: TomerJLevy * add release notes Signed-off-by: TomerJLevy * Return the error as is Signed-off-by: TomerJLevy * revert redundant changes Signed-off-by: TomerJLevy * revert unrelated changes Signed-off-by: TomerJLevy * revert more changes... Signed-off-by: TomerJLevy --------- Signed-off-by: TomerJLevy Co-authored-by: zirain Signed-off-by: shawnh2 --- internal/provider/kubernetes/controller.go | 4 +++- internal/provider/kubernetes/controller_test.go | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 0421c0a8b8..7c0c01664e 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -187,7 +187,9 @@ func isTransientError(err error) bool { kerrors.IsServiceUnavailable(err) || kerrors.IsStoreReadError(err) || kerrors.IsInternalError(err) || - kerrors.IsUnexpectedServerError(err) + kerrors.IsUnexpectedServerError(err) || + errors.Is(err, context.Canceled) || + errors.Is(err, context.DeadlineExceeded) } // Reconcile handles reconciling all resources in a single call. Any resource event should enqueue the diff --git a/internal/provider/kubernetes/controller_test.go b/internal/provider/kubernetes/controller_test.go index a8b33af98a..db0f9a755e 100644 --- a/internal/provider/kubernetes/controller_test.go +++ b/internal/provider/kubernetes/controller_test.go @@ -1034,6 +1034,12 @@ func TestIsTransientError(t *testing.T) { serviceUnavailableErr := kerrors.NewServiceUnavailable("service unavailable") badRequestErr := kerrors.NewBadRequest("bad request") + // new test errors for context + canceledErr := context.Canceled + deadlineExceededErr := context.DeadlineExceeded + wrappedCanceledErr := fmt.Errorf("wrapped: %w", context.Canceled) + wrappedDeadlineExceededErr := fmt.Errorf("wrapped: %w", context.DeadlineExceeded) + testCases := []struct { name string err error @@ -1045,6 +1051,10 @@ func TestIsTransientError(t *testing.T) { {"ServiceUnavailable", serviceUnavailableErr, true}, {"BadRequest", badRequestErr, false}, {"NilError", nil, false}, + {"ContextCanceled", canceledErr, true}, + {"ContextDeadlineExceeded", deadlineExceededErr, true}, + {"WrappedContextCanceled", wrappedCanceledErr, true}, + {"WrappedContextDeadlineExceeded", wrappedDeadlineExceededErr, true}, } for _, tc := range testCases { From a0d90ac1b31c8bcb895b59fb9eee562b73092bff Mon Sep 17 00:00:00 2001 From: shahar-h Date: Mon, 8 Sep 2025 20:06:20 +0300 Subject: [PATCH 2/8] chore: fix CVE (#6903) Signed-off-by: Shahar Harari Signed-off-by: shawnh2 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 36401d3aea..d870c2fedf 100644 --- a/go.mod +++ b/go.mod @@ -435,7 +435,7 @@ require ( github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/tsaarni/x500dn v1.0.0 // indirect - github.com/ulikunitz/xz v0.5.12 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/urfave/cli/v2 v2.27.6 // indirect diff --git a/go.sum b/go.sum index 0e8a048e2a..59795c91e6 100644 --- a/go.sum +++ b/go.sum @@ -1274,8 +1274,8 @@ github.com/tsaarni/x500dn v1.0.0 h1:LvaWTkqRpse4VHBhB5uwf3wytokK4vF9IOyNAEyiA+U= github.com/tsaarni/x500dn v1.0.0/go.mod h1:QaHa3EcUKC4dfCAZmj8+ZRGLKukWgpGv9H3oOCsAbcE= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= -github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= From 5446f0dcb4845640e171be15c9b2910c410a4694 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Wed, 10 Sep 2025 20:18:42 -0700 Subject: [PATCH 3/8] fix: rm incorrectly set exclusiveMaximum field in CRD (#6926) * fix: rm incorrectly set exclusiveMaximum field in CRD * Also fix maximum value to 599 which includes 599 as a valid num Fixes: https://github.com/envoyproxy/gateway/issues/6925 Signed-off-by: Arko Dasgupta Signed-off-by: shawnh2 --- api/v1alpha1/shared_types.go | 3 +- ....envoyproxy.io_backendtrafficpolicies.yaml | 6 +- ....envoyproxy.io_envoyextensionpolicies.yaml | 6 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 24 +++----- ...ateway.envoyproxy.io_securitypolicies.yaml | 24 +++----- ....envoyproxy.io_backendtrafficpolicies.yaml | 6 +- ....envoyproxy.io_envoyextensionpolicies.yaml | 6 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 24 +++----- ...ateway.envoyproxy.io_securitypolicies.yaml | 24 +++----- .../backendtrafficpolicy_test.go | 2 +- test/helm/gateway-crds-helm/all.out.yaml | 60 +++++++------------ .../envoy-gateway-crds.out.yaml | 60 +++++++------------ 12 files changed, 82 insertions(+), 163 deletions(-) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index 8f041feeb0..de2dae7410 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -492,8 +492,7 @@ type KubernetesHorizontalPodAutoscalerSpec struct { // HTTPStatus defines the http status code. // +kubebuilder:validation:Minimum=100 -// +kubebuilder:validation:Maximum=600 -// +kubebuilder:validation:ExclusiveMaximum=true +// +kubebuilder:validation:Maximum=599 type HTTPStatus int // MergeType defines the type of merge operation diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 4aeb42b0aa..8f8269b38f 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -318,8 +318,7 @@ spec: Defaults to 200 only items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1452,8 +1451,7 @@ spec: The retriable-status-codes trigger must also be configured for these status codes to trigger a retry. items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 5e18f20bf8..b430336584 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -416,8 +416,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -842,8 +841,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 8ec65f47c5..b5abb4385c 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -10910,8 +10910,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11378,8 +11377,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11929,8 +11927,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12397,8 +12394,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13037,8 +13033,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13482,8 +13477,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14062,8 +14056,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14505,8 +14498,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index a63bf91625..060dbf0961 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -909,8 +909,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1342,8 +1341,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1826,8 +1824,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2259,8 +2256,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2938,8 +2934,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3382,8 +3377,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3995,8 +3989,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4428,8 +4421,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml index 2f79f196d2..146eb72290 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -317,8 +317,7 @@ spec: Defaults to 200 only items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1451,8 +1450,7 @@ spec: The retriable-status-codes trigger must also be configured for these status codes to trigger a retry. items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index 8ff44012bd..6dc69461d8 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -415,8 +415,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -841,8 +840,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 0a5d48d5bd..8f985254d2 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -10909,8 +10909,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11377,8 +11376,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11928,8 +11926,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12396,8 +12393,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13036,8 +13032,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13481,8 +13476,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14061,8 +14055,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14504,8 +14497,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index da26002a08..0b2ef98782 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -908,8 +908,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1341,8 +1340,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1825,8 +1823,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2258,8 +2255,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2937,8 +2933,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3381,8 +3376,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3994,8 +3988,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4427,8 +4420,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/test/cel-validation/backendtrafficpolicy_test.go b/test/cel-validation/backendtrafficpolicy_test.go index 41e3c75ac0..b040b6a9f8 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -903,7 +903,7 @@ func TestBackendTrafficPolicyTarget(t *testing.T) { } }, wantErrors: []string{ - `spec.HealthCheck.active.http.expectedStatuses[2]: Invalid value: 601: spec.HealthCheck.active.http.expectedStatuses[2] in body should be less than 600`, + `spec.HealthCheck.active.http.expectedStatuses[2]: Invalid value: 601: spec.HealthCheck.active.http.expectedStatuses[2] in body should be less than or equal to 599`, }, }, { diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index b960427d41..6b607224f2 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -17940,8 +17940,7 @@ spec: Defaults to 200 only items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -19074,8 +19073,7 @@ spec: The retriable-status-codes trigger must also be configured for these status codes to trigger a retry. items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -21419,8 +21417,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -21845,8 +21842,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -34300,8 +34296,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -34768,8 +34763,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -35319,8 +35313,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -35787,8 +35780,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -36427,8 +36419,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -36872,8 +36863,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -37452,8 +37442,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -37895,8 +37884,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -39298,8 +39286,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -39731,8 +39718,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -40215,8 +40201,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -40648,8 +40633,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -41327,8 +41311,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -41771,8 +41754,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -42384,8 +42366,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -42817,8 +42798,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index b6a51acff1..4d36077d79 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -628,8 +628,7 @@ spec: Defaults to 200 only items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1762,8 +1761,7 @@ spec: The retriable-status-codes trigger must also be configured for these status codes to trigger a retry. items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4107,8 +4105,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4533,8 +4530,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -16988,8 +16984,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -17456,8 +17451,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -18007,8 +18001,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -18475,8 +18468,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -19115,8 +19107,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -19560,8 +19551,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -20140,8 +20130,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -20583,8 +20572,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -21986,8 +21974,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -22419,8 +22406,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -22903,8 +22889,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -23336,8 +23321,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -24015,8 +23999,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -24459,8 +24442,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -25072,8 +25054,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -25505,8 +25486,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array From 2bc64d0069f579577d32aa34777d5f1dfdf0e561 Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Fri, 12 Sep 2025 23:06:55 +0530 Subject: [PATCH 4/8] fix: validation for grpc routes with extension ref filters (#6949) Signed-off-by: Rudrakh Panigrahi Signed-off-by: shawnh2 --- internal/gatewayapi/filters.go | 2 +- ...croute-with-valid-extension-filter.in.yaml | 48 +++++ ...route-with-valid-extension-filter.out.yaml | 184 ++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.in.yaml create mode 100644 internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index 27c4a93ead..ae8d67eb44 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -136,7 +136,7 @@ func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext, if httpFiltersContext.DirectResponse != nil { break } - if err := ValidateGRPCRouteFilter(&filter); err != nil { + if err := ValidateGRPCRouteFilter(&filter, t.ExtensionGroupKinds...); err != nil { t.processInvalidHTTPFilter(string(filter.Type), httpFiltersContext, err) break } diff --git a/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.in.yaml b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.in.yaml new file mode 100644 index 0000000000..c44e2ca8d0 --- /dev/null +++ b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.in.yaml @@ -0,0 +1,48 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +grpcRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: GRPCRoute + metadata: + namespace: default + name: grpcroute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - method: + service: com.example.Service + type: Exact + backendRefs: + - name: service-1 + port: 8080 + filters: + - type: ExtensionRef + extensionRef: + group: foo.example.io + kind: Foo + name: test +extensionRefFilters: +- apiVersion: foo.example.io/v1alpha1 + kind: Foo + metadata: + name: test + namespace: default + spec: + data: "stuff" diff --git a/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml new file mode 100644 index 0000000000..be7d056cd8 --- /dev/null +++ b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml @@ -0,0 +1,184 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +grpcRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: GRPCRoute + metadata: + creationTimestamp: null + name: grpcroute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + filters: + - extensionRef: + group: foo.example.io + kind: Foo + name: test + type: ExtensionRef + matches: + - method: + service: com.example.Service + type: Exact + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: "" +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + name: envoy-envoy-gateway-gateway-1-196ae069 + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + isHTTP2: true + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: default + name: grpcroute/default/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + name: service-1 + namespace: default + sectionName: "8080" + name: grpcroute/default/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 + extensionRefs: + - object: + apiVersion: foo.example.io/v1alpha1 + kind: Foo + metadata: + name: test + namespace: default + spec: + data: stuff + hostname: '*' + isHTTP2: true + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: default + name: grpcroute/default/grpcroute-1/rule/0/match/0/* + pathMatch: + distinct: false + name: "" + prefix: /com.example.Service + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 From c1ab45a5a2e7a21b1991d5254b13d2d534932261 Mon Sep 17 00:00:00 2001 From: Youssef Rabie Date: Sat, 13 Sep 2025 04:03:23 +0300 Subject: [PATCH 5/8] fix: cleanup dangling route status conditions (#6812) Signed-off-by: y-rabie Signed-off-by: shawnh2 --- internal/provider/kubernetes/status.go | 50 ++- internal/provider/kubernetes/status_test.go | 471 +++++++++++++++++++- 2 files changed, 488 insertions(+), 33 deletions(-) diff --git a/internal/provider/kubernetes/status.go b/internal/provider/kubernetes/status.go index 5712f9aa7f..7de7e92b0f 100644 --- a/internal/provider/kubernetes/status.go +++ b/internal/provider/kubernetes/status.go @@ -104,7 +104,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext panic(err) } hCopy := h.DeepCopy() - hCopy.Status.Parents = mergeRouteParentStatus(h.Namespace, h.Status.Parents, val.Parents) + hCopy.Status.Parents = mergeRouteParentStatus(h.Namespace, r.envoyGateway.Gateway.ControllerName, h.Status.Parents, val.Parents) return hCopy }), }) @@ -134,7 +134,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext panic(err) } gCopy := g.DeepCopy() - gCopy.Status.Parents = mergeRouteParentStatus(g.Namespace, g.Status.Parents, val.Parents) + gCopy.Status.Parents = mergeRouteParentStatus(g.Namespace, r.envoyGateway.Gateway.ControllerName, g.Status.Parents, val.Parents) return gCopy }), }) @@ -166,7 +166,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext panic(err) } tCopy := t.DeepCopy() - tCopy.Status.Parents = mergeRouteParentStatus(t.Namespace, t.Status.Parents, val.Parents) + tCopy.Status.Parents = mergeRouteParentStatus(t.Namespace, r.envoyGateway.Gateway.ControllerName, t.Status.Parents, val.Parents) return tCopy }), }) @@ -198,7 +198,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext panic(err) } tCopy := t.DeepCopy() - tCopy.Status.Parents = mergeRouteParentStatus(t.Namespace, t.Status.Parents, val.Parents) + tCopy.Status.Parents = mergeRouteParentStatus(t.Namespace, r.envoyGateway.Gateway.ControllerName, t.Status.Parents, val.Parents) return tCopy }), }) @@ -230,7 +230,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext panic(err) } uCopy := u.DeepCopy() - uCopy.Status.Parents = mergeRouteParentStatus(u.Namespace, u.Status.Parents, val.Parents) + uCopy.Status.Parents = mergeRouteParentStatus(u.Namespace, r.envoyGateway.Gateway.ControllerName, u.Status.Parents, val.Parents) return uCopy }), }) @@ -501,21 +501,41 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext // mergeRouteParentStatus merges the old and new RouteParentStatus. // This is needed because the RouteParentStatus doesn't support strategic merge patch yet. -func mergeRouteParentStatus(ns string, old, new []gwapiv1.RouteParentStatus) []gwapiv1.RouteParentStatus { - merged := make([]gwapiv1.RouteParentStatus, len(old)) - _ = copy(merged, old) - for _, parent := range new { +func mergeRouteParentStatus(ns, controllerName string, old, new []gwapiv1.RouteParentStatus) []gwapiv1.RouteParentStatus { + // Allocating with worst-case capacity to avoid reallocation. + merged := make([]gwapiv1.RouteParentStatus, 0, len(old)+len(new)) + + // Range over old status parentRefs in order: + // 1. The parentRef exists in the new status: append the new one to the final status. + // 2. The parentRef doesn't exist in the new status and it's not our controller: append it to the final status. + // 3. The parentRef doesn't exist in the new status, and it is our controller: don't append it to the final status. + for _, oldP := range old { found := -1 - for i, existing := range old { - if isParentRefEqual(parent.ParentRef, existing.ParentRef, ns) { - found = i + for newI, newP := range new { + if isParentRefEqual(oldP.ParentRef, newP.ParentRef, ns) { + found = newI break } } if found >= 0 { - merged[found] = parent - } else { - merged = append(merged, parent) + merged = append(merged, new[found]) + } else if oldP.ControllerName != gwapiv1.GatewayController(controllerName) { + merged = append(merged, oldP) + } + } + + // Range over new status parentRefs and make sure every parentRef exists in the final status. If not, append it. + for _, newP := range new { + found := false + for _, mergedP := range merged { + if isParentRefEqual(newP.ParentRef, mergedP.ParentRef, ns) { + found = true + break + } + } + + if !found { + merged = append(merged, newP) } } return merged diff --git a/internal/provider/kubernetes/status_test.go b/internal/provider/kubernetes/status_test.go index 5e81c46135..63b7fdea7f 100644 --- a/internal/provider/kubernetes/status_test.go +++ b/internal/provider/kubernetes/status_test.go @@ -25,11 +25,11 @@ func Test_mergeRouteParentStatus(t *testing.T) { want []gwapiv1.RouteParentStatus }{ { - name: "merge old and new", + name: "old contains one parentRef of ours and one of another controller's, status of ours changed in new.", args: args{ old: []gwapiv1.RouteParentStatus{ { - ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ControllerName: "istio.io/gateway-controller", ParentRef: gwapiv1.ParentReference{ Name: "gateway1", Namespace: ptr.To[gwapiv1.Namespace]("default"), @@ -49,6 +49,24 @@ func Test_mergeRouteParentStatus(t *testing.T) { }, }, }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, }, new: []gwapiv1.RouteParentStatus{ { @@ -59,6 +77,11 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, @@ -68,7 +91,7 @@ func Test_mergeRouteParentStatus(t *testing.T) { }, want: []gwapiv1.RouteParentStatus{ { - ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ControllerName: "istio.io/gateway-controller", ParentRef: gwapiv1.ParentReference{ Name: "gateway1", Namespace: ptr.To[gwapiv1.Namespace]("default"), @@ -96,6 +119,11 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, @@ -103,15 +131,17 @@ func Test_mergeRouteParentStatus(t *testing.T) { }, }, }, - { - name: "override an existing parent", + name: "old contains one parentRef of ours and one of another controller's, status of ours changed in new with an additional parentRef of ours", args: args{ old: []gwapiv1.RouteParentStatus{ { - ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ControllerName: "istio.io/gateway-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway1", + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), }, Conditions: []metav1.Condition{ { @@ -129,8 +159,7 @@ func Test_mergeRouteParentStatus(t *testing.T) { { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway2", - Namespace: ptr.To[gwapiv1.Namespace]("default"), + Name: "gateway2", }, Conditions: []metav1.Condition{ { @@ -155,18 +184,44 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, }, }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, }, }, want: []gwapiv1.RouteParentStatus{ { - ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ControllerName: "istio.io/gateway-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway1", + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), }, Conditions: []metav1.Condition{ { @@ -189,22 +244,229 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, }, }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + }, + { + name: "old contains one parentRef of ours and one of another controller's, ours gets dropped in new and a different parentRef of ours is added", + args: args{ + old: []gwapiv1.RouteParentStatus{ + { + ControllerName: "istio.io/gateway-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + new: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + }, + want: []gwapiv1.RouteParentStatus{ + { + ControllerName: "istio.io/gateway-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + }, + // Practically this will never occur, since having no parentRefs in the new + // status means the route doesn't attach (in the spec) to any of our gateways. + // + // But then we'd consider it irrelevant before ever computing such status for it, i.e, the + // route will forever have a dangling status parentRef referencing us that will not be removed. + // + // TODO: maybe this needs to be fixed. + { + name: "old contains one parentRef of ours and one of another controller's, ours gets dropped in new.", + args: args{ + old: []gwapiv1.RouteParentStatus{ + { + ControllerName: "istio.io/gateway-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + new: []gwapiv1.RouteParentStatus{}, + }, + want: []gwapiv1.RouteParentStatus{ + { + ControllerName: "istio.io/gateway-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway1", + Namespace: ptr.To[gwapiv1.Namespace]("default"), + SectionName: ptr.To[gwapiv1.SectionName]("listener1"), + Port: ptr.To[gwapiv1.PortNumber](80), + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, }, }, { - name: "nothing changed", + name: "old contains one parentRef of ours, status of ours changed in new.", args: args{ old: []gwapiv1.RouteParentStatus{ { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway1", + Name: "gateway2", }, Conditions: []metav1.Condition{ { @@ -219,6 +481,8 @@ func Test_mergeRouteParentStatus(t *testing.T) { }, }, }, + }, + new: []gwapiv1.RouteParentStatus{ { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", ParentRef: gwapiv1.ParentReference{ @@ -227,12 +491,62 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, }, }, }, + }, + want: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + Reason: "SomeReason", + }, + }, + }, + }, + }, + { + name: "old contains one parentRef of ours, status of ours changed in new with an additional parentRef of ours", + args: args{ + old: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, new: []gwapiv1.RouteParentStatus{ { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", @@ -242,18 +556,59 @@ func Test_mergeRouteParentStatus(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), Status: metav1.ConditionFalse, Reason: "SomeReason", }, }, }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, }, }, want: []gwapiv1.RouteParentStatus{ { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway1", + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionFalse, + Reason: "SomeReason", + }, + }, + }, + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", }, Conditions: []metav1.Condition{ { @@ -268,25 +623,105 @@ func Test_mergeRouteParentStatus(t *testing.T) { }, }, }, + }, + }, + { + name: "old contains one parentRef of ours, ours gets dropped in new and a different parentRef of ours is added", + args: args{ + old: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + new: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway3", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + }, + want: []gwapiv1.RouteParentStatus{ { ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", ParentRef: gwapiv1.ParentReference{ - Name: "gateway2", + Name: "gateway3", }, Conditions: []metav1.Condition{ { Type: string(gwapiv1.RouteConditionAccepted), - Status: metav1.ConditionFalse, - Reason: "SomeReason", + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, + }, + }, + }, + }, + // Similar note about practicality of occurrence. + { + name: "old contains one parentRef of ours, and it gets dropped in new.", + args: args{ + old: []gwapiv1.RouteParentStatus{ + { + ControllerName: "gateway.envoyproxy.io/gatewayclass-controller", + ParentRef: gwapiv1.ParentReference{ + Name: "gateway2", + }, + Conditions: []metav1.Condition{ + { + Type: string(gwapiv1.RouteConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + }, + { + Type: string(gwapiv1.RouteConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: "ResolvedRefs", + }, }, }, }, + new: []gwapiv1.RouteParentStatus{}, }, + want: []gwapiv1.RouteParentStatus{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := mergeRouteParentStatus("default", tt.args.old, tt.args.new); !reflect.DeepEqual(got, tt.want) { + if got := mergeRouteParentStatus("default", "gateway.envoyproxy.io/gatewayclass-controller", tt.args.old, tt.args.new); !reflect.DeepEqual(got, tt.want) { t.Errorf("mergeRouteParentStatus() = %v, want %v", got, tt.want) } }) From 19326e38f4d71ecef130c5f2ed7888de2546d3a6 Mon Sep 17 00:00:00 2001 From: Sudipto Baral Date: Sat, 13 Sep 2025 01:53:53 -0400 Subject: [PATCH 6/8] Fix: Add missing patch annotations to Compression struct for proper Merge (#6951) * fix: merge compression annotation Signed-off-by: sudipto baral * test: add more compression merge test cases Signed-off-by: sudipto baral --------- Signed-off-by: sudipto baral Signed-off-by: shawnh2 --- api/v1alpha1/backendtrafficpolicy_types.go | 5 +- ...afficpolicy-compression-json-merge.in.yaml | 63 +++ ...fficpolicy-compression-json-merge.out.yaml | 249 ++++++++++ ...policy-compression-strategic-merge.in.yaml | 126 +++++ ...olicy-compression-strategic-merge.out.yaml | 463 ++++++++++++++++++ 5 files changed, 905 insertions(+), 1 deletion(-) create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.in.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.in.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml diff --git a/api/v1alpha1/backendtrafficpolicy_types.go b/api/v1alpha1/backendtrafficpolicy_types.go index 1afe9c48da..ecda554aa9 100644 --- a/api/v1alpha1/backendtrafficpolicy_types.go +++ b/api/v1alpha1/backendtrafficpolicy_types.go @@ -74,8 +74,11 @@ type BackendTrafficPolicySpec struct { // The compression config for the http streams. // + // +patchMergeKey=type + // +patchStrategy=merge + // // +optional - Compression []*Compression `json:"compression,omitempty"` + Compression []*Compression `json:"compression,omitempty" patchMergeKey:"type" patchStrategy:"merge"` // ResponseOverride defines the configuration to override specific responses with a custom one. // If multiple configurations are specified, the first one to match wins. diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.in.yaml new file mode 100644 index 0000000000..2ccb740ee9 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.in.yaml @@ -0,0 +1,63 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 +backendTrafficPolicies: + # Gateway-level policy + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: envoy-gateway + name: gateway-compression-policy + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + compression: + - type: Gzip + # Route-level policy + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: route-compression-policy + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + compression: + - type: Brotli + mergeType: JSONMerge diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml new file mode 100644 index 0000000000..fb49d6bfb4 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml @@ -0,0 +1,249 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: route-compression-policy + namespace: default + spec: + compression: + - type: Brotli + mergeType: JSONMerge + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Merged with policy envoy-gateway/gateway-compression-policy + reason: Merged + status: "True" + type: Merged + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: gateway-compression-policy + namespace: envoy-gateway + spec: + compression: + - type: Gzip + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: 'This policy is being merged by other backendTrafficPolicies for + these routes: [default/httproute-1]' + reason: Merged + status: "True" + type: Merged + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + traffic: + compression: + - type: Brotli + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.in.yaml new file mode 100644 index 0000000000..f09c3a93d3 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.in.yaml @@ -0,0 +1,126 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/api" + backendRefs: + - name: service-2 + port: 8080 + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-3 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/admin" + backendRefs: + - name: service-3 + port: 8080 +backendTrafficPolicies: + # Gateway-level policy + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: envoy-gateway + name: gateway-compression-policy + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + compression: + - type: Gzip + # Route-level policy with StrategicMerge + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: route-compression-policy + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + compression: + - type: Brotli + mergeType: StrategicMerge + # Route-level policy without mergeType (should not merge with gateway policy) + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: route-compression-policy-no-merge + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-2 + compression: + - type: Brotli + # Route-level policy with StrategicMerge but no compression (should inherit from gateway) + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: default + name: route-compression-policy-inherit + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-3 + mergeType: StrategicMerge diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml new file mode 100644 index 0000000000..dd68160112 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml @@ -0,0 +1,463 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: route-compression-policy + namespace: default + spec: + compression: + - type: Brotli + mergeType: StrategicMerge + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Merged with policy envoy-gateway/gateway-compression-policy + reason: Merged + status: "True" + type: Merged + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: route-compression-policy-no-merge + namespace: default + spec: + compression: + - type: Brotli + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-2 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: route-compression-policy-inherit + namespace: default + spec: + mergeType: StrategicMerge + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-3 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Merged with policy envoy-gateway/gateway-compression-policy + reason: Merged + status: "True" + type: Merged + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: gateway-compression-policy + namespace: envoy-gateway + spec: + compression: + - type: Gzip + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: 'This policy is being merged by other backendTrafficPolicies for + these routes: [default/httproute-1 default/httproute-3]' + reason: Merged + status: "True" + type: Merged + - lastTransitionTime: null + message: 'This policy is being overridden by other backendTrafficPolicies + for these routes: [default/httproute-2]' + reason: Overridden + status: "True" + type: Overridden + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 3 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-2 + port: 8080 + matches: + - path: + value: /api + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-3 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-3 + port: 8080 + matches: + - path: + value: /admin + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-3 + namespace: default + name: httproute/default/httproute-3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + name: service-3 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-3/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-3 + namespace: default + name: httproute/default/httproute-3/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /admin + traffic: + compression: + - type: Gzip + - destination: + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + name: service-2 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-2/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /api + traffic: + compression: + - type: Brotli + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + traffic: + compression: + - type: Brotli + - type: Gzip + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 From ef9df3e65e5c2d57f4bcbba082e0a19a4e8f5e7d Mon Sep 17 00:00:00 2001 From: shahar-h Date: Sun, 14 Sep 2025 18:27:24 +0300 Subject: [PATCH 7/8] fix: update distroless image to resolve glibc CVEs (#6953) Signed-off-by: Shahar Harari Signed-off-by: shawnh2 --- tools/docker/envoy-gateway/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/envoy-gateway/Dockerfile b/tools/docker/envoy-gateway/Dockerfile index cec7a9eec1..9d2ab4f36c 100644 --- a/tools/docker/envoy-gateway/Dockerfile +++ b/tools/docker/envoy-gateway/Dockerfile @@ -4,7 +4,7 @@ RUN mkdir -p /var/lib/eg # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/base-nossl:nonroot@sha256:d1fc914c43cea489c26c896721344a49a1761b9bb678bcba1758772d22913302 +FROM gcr.io/distroless/base-nossl:nonroot@sha256:a1922debbf4ff2cc245d7c0d1e2021cfcee35fe24afae7505aeec59f7e7802f6 ARG TARGETPLATFORM COPY --chown=65532:65532 $TARGETPLATFORM/envoy-gateway /usr/local/bin/ COPY --from=source --chown=65532:65532 /var/lib /var/lib From eab96a52366622eab02e2a74b07c098476db696e Mon Sep 17 00:00:00 2001 From: shawnh2 Date: Mon, 15 Sep 2025 20:09:09 +0800 Subject: [PATCH 8/8] fix gen-check Signed-off-by: shawnh2 --- ...fficpolicy-compression-json-merge.out.yaml | 27 ------------ ...olicy-compression-strategic-merge.out.yaml | 43 ------------------- ...route-with-valid-extension-filter.out.yaml | 26 ----------- 3 files changed, 96 deletions(-) diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml index fb49d6bfb4..b562cf3548 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-json-merge.out.yaml @@ -168,9 +168,6 @@ infraIR: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - ownerReference: - kind: GatewayClass - name: envoy-gateway-class name: envoy-gateway/gateway-1 namespace: envoy-gateway-system xdsIR: @@ -178,24 +175,8 @@ xdsIR: accessLog: json: - path: /dev/stdout - globalResources: - proxyServiceCluster: - name: envoy-gateway/gateway-1 - settings: - - addressType: IP - endpoints: - - host: 7.6.5.4 - port: 8080 - zone: zone1 - metadata: - name: envoy-envoy-gateway-gateway-1-196ae069 - namespace: envoy-gateway-system - sectionName: "8080" - name: envoy-gateway/gateway-1 - protocol: TCP http: - address: 0.0.0.0 - externalPort: 80 hostnames: - '*' isHTTP2: false @@ -211,20 +192,12 @@ xdsIR: port: 10080 routes: - destination: - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default name: httproute/default/httproute-1/rule/0 settings: - addressType: IP endpoints: - host: 7.7.7.7 port: 8080 - metadata: - name: service-1 - namespace: default - sectionName: "8080" name: httproute/default/httproute-1/rule/0/backend/0 protocol: HTTP weight: 1 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml index dd68160112..0586cc0ce8 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression-strategic-merge.out.yaml @@ -317,9 +317,6 @@ infraIR: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - ownerReference: - kind: GatewayClass - name: envoy-gateway-class name: envoy-gateway/gateway-1 namespace: envoy-gateway-system xdsIR: @@ -327,24 +324,8 @@ xdsIR: accessLog: json: - path: /dev/stdout - globalResources: - proxyServiceCluster: - name: envoy-gateway/gateway-1 - settings: - - addressType: IP - endpoints: - - host: 7.6.5.4 - port: 8080 - zone: zone1 - metadata: - name: envoy-envoy-gateway-gateway-1-196ae069 - namespace: envoy-gateway-system - sectionName: "8080" - name: envoy-gateway/gateway-1 - protocol: TCP http: - address: 0.0.0.0 - externalPort: 80 hostnames: - '*' isHTTP2: false @@ -360,20 +341,12 @@ xdsIR: port: 10080 routes: - destination: - metadata: - kind: HTTPRoute - name: httproute-3 - namespace: default name: httproute/default/httproute-3/rule/0 settings: - addressType: IP endpoints: - host: 7.7.7.7 port: 8080 - metadata: - name: service-3 - namespace: default - sectionName: "8080" name: httproute/default/httproute-3/rule/0/backend/0 protocol: HTTP weight: 1 @@ -392,20 +365,12 @@ xdsIR: compression: - type: Gzip - destination: - metadata: - kind: HTTPRoute - name: httproute-2 - namespace: default name: httproute/default/httproute-2/rule/0 settings: - addressType: IP endpoints: - host: 7.7.7.7 port: 8080 - metadata: - name: service-2 - namespace: default - sectionName: "8080" name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 @@ -424,20 +389,12 @@ xdsIR: compression: - type: Brotli - destination: - metadata: - kind: HTTPRoute - name: httproute-1 - namespace: default name: httproute/default/httproute-1/rule/0 settings: - addressType: IP endpoints: - host: 7.7.7.7 port: 8080 - metadata: - name: service-1 - namespace: default - sectionName: "8080" name: httproute/default/httproute-1/rule/0/backend/0 protocol: HTTP weight: 1 diff --git a/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml index be7d056cd8..7280e9f6a5 100644 --- a/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml +++ b/internal/gatewayapi/testdata/extensions/grpcroute-with-valid-extension-filter.out.yaml @@ -98,9 +98,6 @@ infraIR: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - ownerReference: - kind: GatewayClass - name: envoy-gateway-class name: envoy-gateway/gateway-1 namespace: "" xdsIR: @@ -108,23 +105,8 @@ xdsIR: accessLog: json: - path: /dev/stdout - globalResources: - proxyServiceCluster: - name: envoy-gateway/gateway-1 - settings: - - addressType: IP - endpoints: - - host: 7.6.5.4 - port: 8080 - zone: zone1 - metadata: - name: envoy-envoy-gateway-gateway-1-196ae069 - sectionName: "8080" - name: envoy-gateway/gateway-1 - protocol: TCP http: - address: 0.0.0.0 - externalPort: 80 hostnames: - '*' isHTTP2: true @@ -140,20 +122,12 @@ xdsIR: port: 10080 routes: - destination: - metadata: - kind: GRPCRoute - name: grpcroute-1 - namespace: default name: grpcroute/default/grpcroute-1/rule/0 settings: - addressType: IP endpoints: - host: 7.7.7.7 port: 8080 - metadata: - name: service-1 - namespace: default - sectionName: "8080" name: grpcroute/default/grpcroute-1/rule/0/backend/0 protocol: GRPC weight: 1