From 6e0fa64ec6c1a0dc7fad0a3e112d237668ea7716 Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Tue, 12 Aug 2025 17:49:59 -0500 Subject: [PATCH 01/27] fix: cluster stat name: lowercase Kind (#6780) cluster stat name: lowercase Kind Signed-off-by: Guy Daich Signed-off-by: zirain --- internal/gatewayapi/route.go | 2 +- .../gatewayapi/testdata/envoyproxy-with-statname.out.yaml | 6 +++--- release-notes/current.yaml | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 4fde9fcaef..35b114b980 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -2083,7 +2083,7 @@ func getStatPattern(routeContext RouteContext, parentRef *RouteParentContext) st func buildStatName(pattern string, route RouteContext, ruleName *gwapiv1.SectionName, idx int, refs []string) string { statName := strings.ReplaceAll(pattern, egv1a1.StatFormatterRouteName, route.GetName()) statName = strings.ReplaceAll(statName, egv1a1.StatFormatterRouteNamespace, route.GetNamespace()) - statName = strings.ReplaceAll(statName, egv1a1.StatFormatterRouteKind, route.GetObjectKind().GroupVersionKind().Kind) + statName = strings.ReplaceAll(statName, egv1a1.StatFormatterRouteKind, strings.ToLower(route.GetObjectKind().GroupVersionKind().Kind)) if ruleName == nil { statName = strings.ReplaceAll(statName, egv1a1.StatFormatterRouteRuleName, "-") } else { diff --git a/internal/gatewayapi/testdata/envoyproxy-with-statname.out.yaml b/internal/gatewayapi/testdata/envoyproxy-with-statname.out.yaml index 9c194246aa..59ced8aa6b 100644 --- a/internal/gatewayapi/testdata/envoyproxy-with-statname.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-with-statname.out.yaml @@ -230,7 +230,7 @@ xdsIR: name: httproute/default/httproute-1/rule/0/backend/1 protocol: HTTP weight: 1 - statName: HTTPRoute/default/httproute-1/foo/0/default/service-3|default/service-4 + statName: httproute/default/httproute-1/foo/0/default/service-3|default/service-4 hostname: gateway.envoyproxy.io isHTTP2: false metadata: @@ -262,7 +262,7 @@ xdsIR: name: httproute/default/httproute-1/rule/1/backend/0 protocol: HTTP weight: 1 - statName: HTTPRoute/default/httproute-1/fallback/1/default/service-1 + statName: httproute/default/httproute-1/fallback/1/default/service-1 hostname: gateway.envoyproxy.io isHTTP2: false metadata: @@ -326,7 +326,7 @@ xdsIR: name: grpcroute/default/grpcroute-1/rule/0/backend/3 protocol: GRPC weight: 1 - statName: GRPCRoute/default/grpcroute-1/-/0/default/service-1|default/service-2|default/service-3|default/service-4 + statName: grpcroute/default/grpcroute-1/-/0/default/service-1|default/service-2|default/service-3|default/service-4 hostname: '*' isHTTP2: true metadata: diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 3271a4f907..ed00bf3e75 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -10,6 +10,7 @@ security updates: | new features: | bug fixes: | + Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. # Enhancements that improve performance. performance improvements: | From 9b340eca3736261bb65a1de9d7552ad348f6222a Mon Sep 17 00:00:00 2001 From: Youssef Rabie Date: Wed, 13 Aug 2025 17:23:55 +0300 Subject: [PATCH 02/27] fix: envoy service cluster name for zone-aware routing (#6763) * fix!: fix envoy service cluster name for zone-aware routing Signed-off-by: y-rabie * extend e2e tests for zone aware routing Signed-off-by: y-rabie * extend unit tests for zone aware routing Signed-off-by: y-rabie --------- Signed-off-by: y-rabie Signed-off-by: zirain --- internal/provider/kubernetes/controller.go | 61 +++++- .../provider/kubernetes/controller_test.go | 186 ++++++++++++++++++ ...e-aware-routing-btp-force-local-zone.yaml} | 12 +- ...aware-routing-btp-no-force-local-zone.yaml | 47 +++++ .../testdata/zone-aware-routing-gateways.yaml | 91 +++++++++ test/e2e/tests/weighted_backend.go | 18 +- test/e2e/tests/zone_aware_routing.go | 59 +++++- 7 files changed, 448 insertions(+), 26 deletions(-) rename test/e2e/testdata/{zone-aware-routing-btp-enabled.yaml => zone-aware-routing-btp-force-local-zone.yaml} (81%) create mode 100644 test/e2e/testdata/zone-aware-routing-btp-no-force-local-zone.yaml create mode 100644 test/e2e/testdata/zone-aware-routing-gateways.yaml diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index cd486b36c3..dbf310280f 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -1380,7 +1380,8 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g mergedGateways := false if r.mergeGateways.Has(managedGC.Name) { mergedGateways = true - r.processServiceCluster(managedGC.Name, resourceMap) + // processGatewayClassParamsRef has been called for this gatewayclass, its EnvoyProxy should exist in resourceTree + r.processServiceClusterForGatewayClass(resourceTree.EnvoyProxyForGatewayClass, managedGC, resourceMap) } for _, gtw := range gatewayList.Items { @@ -1422,10 +1423,6 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g gtwNamespacedName := utils.NamespacedName(>w).String() - if !mergedGateways { - r.processServiceCluster(gtwNamespacedName, resourceMap) - } - // Route Processing if r.tlsRouteCRDExists { @@ -1478,6 +1475,15 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g r.log.Error(err, "failed to process infrastructure.parametersRef for gateway", "namespace", gtw.Namespace, "name", gtw.Name) } + if !mergedGateways { + var ep *egv1a1.EnvoyProxy = nil + if gtw.Spec.Infrastructure != nil && gtw.Spec.Infrastructure.ParametersRef != nil { + // processGatewayParamsRef has been called for this gateway, its EnvoyProxy should exist in resourceTree + ep = resourceTree.GetEnvoyProxy(gtw.Namespace, gtw.Spec.Infrastructure.ParametersRef.Name) + } + r.processServiceClusterForGateway(ep, >w, resourceMap) + } + if !resourceMap.allAssociatedGateways.Has(gtwNamespacedName) { resourceMap.allAssociatedGateways.Insert(gtwNamespacedName) resourceTree.Gateways = append(resourceTree.Gateways, >w) @@ -1487,16 +1493,55 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g return nil } -func (r *gatewayAPIReconciler) processServiceCluster(resourceName string, resourceMap *resourceMappings) { +// Called on a GatewayClass when merged gateways mode is enabled for it. +func (r *gatewayAPIReconciler) processServiceClusterForGatewayClass(ep *egv1a1.EnvoyProxy, gatewayClass *gwapiv1.GatewayClass, resourceMap *resourceMappings) { // Skip processing if topology injector is disabled if r.envoyGateway != nil && r.envoyGateway.TopologyInjectorDisabled() { return } - proxySvcName := proxy.ExpectedResourceHashedName(resourceName) + proxySvcName, proxySvcNamespace := proxy.ExpectedResourceHashedName(gatewayClass.Name), r.namespace + + // Check if the service name was specified in EnvoyProxy + if ep != nil { + provider := ep.GetEnvoyProxyProvider() + if provider.Kubernetes != nil && provider.Kubernetes.EnvoyService != nil && provider.Kubernetes.EnvoyService.Name != nil { + proxySvcName = *provider.Kubernetes.EnvoyService.Name + } + } + + resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{ + Kind: ptr.To(gwapiv1.Kind("Service")), + Namespace: gatewayapi.NamespacePtr(proxySvcNamespace), + Name: gwapiv1.ObjectName(proxySvcName), + }) +} + +// Called on a Gateway when merged gateways mode is not enabled for its parent GatewayClass. +func (r *gatewayAPIReconciler) processServiceClusterForGateway(ep *egv1a1.EnvoyProxy, gateway *gwapiv1.Gateway, resourceMap *resourceMappings) { + // Skip processing if topology injector is disabled + if r.envoyGateway != nil && r.envoyGateway.TopologyInjectorDisabled() { + return + } + + proxySvcName, proxySvcNamespace := proxy.ExpectedResourceHashedName(utils.NamespacedName(gateway).String()), r.namespace + // Check if gateway namespaced mode is used. If it is, the service's name is the same as + // the gateway's and it lives in the gateway's namespace not the controller's. + if r.gatewayNamespaceMode { + proxySvcName, proxySvcNamespace = gateway.Name, gateway.Namespace + } + + // Check if the service name was specified in EnvoyProxy + if ep != nil { + provider := ep.GetEnvoyProxyProvider() + if provider.Kubernetes != nil && provider.Kubernetes.EnvoyService != nil && provider.Kubernetes.EnvoyService.Name != nil { + proxySvcName = *provider.Kubernetes.EnvoyService.Name + } + } + resourceMap.allAssociatedBackendRefs.Insert(gwapiv1.BackendObjectReference{ Kind: ptr.To(gwapiv1.Kind("Service")), - Namespace: gatewayapi.NamespacePtr(r.namespace), + Namespace: gatewayapi.NamespacePtr(proxySvcNamespace), Name: gwapiv1.ObjectName(proxySvcName), }) } diff --git a/internal/provider/kubernetes/controller_test.go b/internal/provider/kubernetes/controller_test.go index 523940bb46..bb23b27be9 100644 --- a/internal/provider/kubernetes/controller_test.go +++ b/internal/provider/kubernetes/controller_test.go @@ -30,6 +30,7 @@ import ( "github.com/envoyproxy/gateway/internal/envoygateway/config" "github.com/envoyproxy/gateway/internal/gatewayapi" "github.com/envoyproxy/gateway/internal/gatewayapi/resource" + "github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/proxy" "github.com/envoyproxy/gateway/internal/logging" "github.com/envoyproxy/gateway/internal/provider/kubernetes/test" "github.com/envoyproxy/gateway/internal/utils" @@ -1247,6 +1248,191 @@ func TestProcessSecurityPolicyObjectRefs(t *testing.T) { } } +func TestProcessServiceClusterForGatewayClass(t *testing.T) { + testCases := []struct { + name string + gatewayClass *gwapiv1.GatewayClass + envoyProxy *egv1a1.EnvoyProxy + expectedSvcName string + }{ + { + name: "when merged gateways and no hardcoded svc name is used", + gatewayClass: &gwapiv1.GatewayClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "merged-gc", + }, + }, + envoyProxy: nil, + expectedSvcName: proxy.ExpectedResourceHashedName("merged-gc"), + }, + { + name: "when merged gateways and a hardcoded svc name is used", + gatewayClass: &gwapiv1.GatewayClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "merged-gc", + }, + }, + envoyProxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "merged-gc", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Name: ptr.To("merged-gc-svc"), + }, + }, + }, + }, + }, + expectedSvcName: "merged-gc-svc", + }, + } + + for i := range testCases { + tc := testCases[i] + // Run the test cases. + t.Run(tc.name, func(t *testing.T) { + logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo) + resourceMap := newResourceMapping() + + r := newGatewayAPIReconciler(logger) + r.namespace = "envoy-gateway-system" + + r.processServiceClusterForGatewayClass(tc.envoyProxy, tc.gatewayClass, resourceMap) + + require.Contains(t, resourceMap.allAssociatedBackendRefs, gwapiv1.BackendObjectReference{ + Kind: ptr.To(gwapiv1.Kind("Service")), + Namespace: gatewayapi.NamespacePtr(r.namespace), + Name: gwapiv1.ObjectName(tc.expectedSvcName), + }) + }) + } +} + +func TestProcessServiceClusterForGateway(t *testing.T) { + testCases := []struct { + name string + gateway *gwapiv1.Gateway + envoyProxy *egv1a1.EnvoyProxy + gatewayNamespacedMode bool + expectedSvcName string + expectedSvcNamespace string + }{ + { + name: "no gateway namespaced mode with no hardcoded service name", + gateway: &gwapiv1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + Namespace: "app-namespace", + }, + }, + envoyProxy: nil, + gatewayNamespacedMode: false, + expectedSvcName: "", + expectedSvcNamespace: "", + }, + { + name: "no gateway namespaced mode with hardcoded service name", + gateway: &gwapiv1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + Namespace: "app-namespace", + }, + }, + envoyProxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Name: ptr.To("my-gateway-svc"), + }, + }, + }, + }, + }, + gatewayNamespacedMode: false, + expectedSvcName: "my-gateway-svc", + expectedSvcNamespace: "", + }, + { + name: "gateway namespaced mode with no hardcoded service name", + gateway: &gwapiv1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + Namespace: "app-namespace", + }, + }, + envoyProxy: nil, + gatewayNamespacedMode: true, + expectedSvcName: "my-gateway", + expectedSvcNamespace: "app-namespace", + }, + { + name: "gateway namespaced mode with hardcoded service name", + gateway: &gwapiv1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + Namespace: "app-namespace", + }, + }, + envoyProxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Name: ptr.To("my-gateway-svc"), + }, + }, + }, + }, + }, + gatewayNamespacedMode: true, + expectedSvcName: "my-gateway-svc", + expectedSvcNamespace: "app-namespace", + }, + } + + for i := range testCases { + tc := testCases[i] + // Run the test cases. + t.Run(tc.name, func(t *testing.T) { + logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo) + resourceMap := newResourceMapping() + + r := newGatewayAPIReconciler(logger) + r.namespace = "envoy-gateway-system" + r.gatewayNamespaceMode = tc.gatewayNamespacedMode + + if tc.expectedSvcNamespace == "" { + tc.expectedSvcNamespace = r.namespace + } + + if tc.expectedSvcName == "" { + tc.expectedSvcName = proxy.ExpectedResourceHashedName(utils.NamespacedName(tc.gateway).String()) + } + + r.processServiceClusterForGateway(tc.envoyProxy, tc.gateway, resourceMap) + + require.Contains(t, resourceMap.allAssociatedBackendRefs, gwapiv1.BackendObjectReference{ + Kind: ptr.To(gwapiv1.Kind("Service")), + Namespace: gatewayapi.NamespacePtr(tc.expectedSvcNamespace), + Name: gwapiv1.ObjectName(tc.expectedSvcName), + }) + }) + } +} + func newGatewayAPIReconciler(logger logging.Logger) *gatewayAPIReconciler { return &gatewayAPIReconciler{ log: logger, diff --git a/test/e2e/testdata/zone-aware-routing-btp-enabled.yaml b/test/e2e/testdata/zone-aware-routing-btp-force-local-zone.yaml similarity index 81% rename from test/e2e/testdata/zone-aware-routing-btp-enabled.yaml rename to test/e2e/testdata/zone-aware-routing-btp-force-local-zone.yaml index 28536127b8..eadc25c0f7 100644 --- a/test/e2e/testdata/zone-aware-routing-btp-enabled.yaml +++ b/test/e2e/testdata/zone-aware-routing-btp-force-local-zone.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Service metadata: - name: btp-zone-aware + name: btp-force-local-zone namespace: gateway-conformance-infra spec: selector: @@ -15,7 +15,7 @@ spec: apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: - name: btp-zone-aware + name: btp-force-local-zone namespace: gateway-conformance-infra spec: parentRefs: @@ -24,22 +24,22 @@ spec: - matches: - path: type: PathPrefix - value: /btp-zone-aware + value: /btp-force-local-zone backendRefs: - - name: btp-zone-aware + - name: btp-force-local-zone port: 8080 weight: 1 --- apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: - name: btp-zone-aware + name: btp-force-local-zone namespace: gateway-conformance-infra spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute - name: btp-zone-aware + name: btp-force-local-zone loadBalancer: type: RoundRobin zoneAware: diff --git a/test/e2e/testdata/zone-aware-routing-btp-no-force-local-zone.yaml b/test/e2e/testdata/zone-aware-routing-btp-no-force-local-zone.yaml new file mode 100644 index 0000000000..740896187c --- /dev/null +++ b/test/e2e/testdata/zone-aware-routing-btp-no-force-local-zone.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: Service +metadata: + name: btp-no-force-local-zone + namespace: gateway-conformance-infra +spec: + selector: + app: zone-aware-backend + ports: + - protocol: TCP + port: 8080 + name: http11 + targetPort: 3000 +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: btp-no-force-local-zone + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: /btp-no-force-local-zone + backendRefs: + - name: btp-no-force-local-zone + port: 8080 + weight: 1 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: btp-no-force-local-zone + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: btp-no-force-local-zone + loadBalancer: + type: RoundRobin + zoneAware: + preferLocal: + minEndpointsThreshold: 1 diff --git a/test/e2e/testdata/zone-aware-routing-gateways.yaml b/test/e2e/testdata/zone-aware-routing-gateways.yaml new file mode 100644 index 0000000000..90d6781697 --- /dev/null +++ b/test/e2e/testdata/zone-aware-routing-gateways.yaml @@ -0,0 +1,91 @@ +# zone-aware-routing-gtw should be similar to `same-namespace` gateway, only difference +# is having a hard-coded service name in the EnvoyProxy attached, to test zone-aware-routing +# in that case when no ForceLocal is specified. +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: zone-aware-routing-gtw + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + - name: tls + protocol: TLS + port: 443 + tls: + mode: Passthrough + allowedRoutes: + namespaces: + from: Same + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: zone-aware-routing +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: zone-aware-routing + namespace: gateway-conformance-infra +spec: + ipFamily: IPv4 + provider: + type: Kubernetes + kubernetes: + envoyService: + name: zone-aware-routing-gtw +--- +apiVersion: v1 +kind: Service +metadata: + name: btp-no-force-local-zone-hardcoded-svc-name + namespace: gateway-conformance-infra +spec: + selector: + app: zone-aware-backend + ports: + - protocol: TCP + port: 8080 + name: http11 + targetPort: 3000 +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: btp-no-force-local-zone-hardcoded-svc-name + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: zone-aware-routing-gtw + rules: + - matches: + - path: + type: PathPrefix + value: /btp-no-force-local-zone-hardcoded-svc-name + backendRefs: + - name: btp-no-force-local-zone-hardcoded-svc-name + port: 8080 + weight: 1 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: btp-no-force-local-zone-hardcoded-svc-name + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: btp-no-force-local-zone-hardcoded-svc-name + loadBalancer: + type: RoundRobin + zoneAware: + preferLocal: + minEndpointsThreshold: 1 diff --git a/test/e2e/tests/weighted_backend.go b/test/e2e/tests/weighted_backend.go index 154c6f5fbf..51fc0d1cb6 100644 --- a/test/e2e/tests/weighted_backend.go +++ b/test/e2e/tests/weighted_backend.go @@ -39,7 +39,7 @@ var WeightedBackendTest = suite.ConformanceTest{ "infra-backend-v1": sendRequests * .5, "infra-backend-v2": sendRequests * .5, } - runWeightedBackendTest(t, suite, "weight-equal-http-route", "/same-weight", "infra-backend", expected) + runWeightedBackendTest(t, suite, nil, "weight-equal-http-route", "/same-weight", "infra-backend", expected) }) t.Run("BlueGreen", func(t *testing.T) { // The received request is approximately 9:1 @@ -47,7 +47,7 @@ var WeightedBackendTest = suite.ConformanceTest{ "infra-backend-v1": sendRequests * .9, "infra-backend-v2": sendRequests * .1, } - runWeightedBackendTest(t, suite, "weight-bluegreen-http-route", "/blue-green", "infra-backend", expected) + runWeightedBackendTest(t, suite, nil, "weight-bluegreen-http-route", "/blue-green", "infra-backend", expected) }) t.Run("CompleteRollout", func(t *testing.T) { // All the requests should be proxied to v1 @@ -55,16 +55,20 @@ var WeightedBackendTest = suite.ConformanceTest{ "infra-backend-v1": sendRequests * 1, "infra-backend-v2": sendRequests * 0, } - runWeightedBackendTest(t, suite, "weight-complete-rollout-http-route", "/complete-rollout", "infra-backend", expected) + runWeightedBackendTest(t, suite, nil, "weight-complete-rollout-http-route", "/complete-rollout", "infra-backend", expected) }) }, } -func runWeightedBackendTest(t *testing.T, suite *suite.ConformanceTestSuite, routeName, path, backendName string, expectedOutput map[string]int) { +func runWeightedBackendTest(t *testing.T, suite *suite.ConformanceTestSuite, gateway *types.NamespacedName, routeName, path, backendName string, expectedOutput map[string]int) { weightEqualRoute := types.NamespacedName{Name: routeName, Namespace: ConformanceInfraNamespace} - gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, - suite.ControllerName, - kubernetes.NewGatewayRef(SameNamespaceGateway), weightEqualRoute) + + gatewayRef := kubernetes.NewGatewayRef(SameNamespaceGateway) + if gateway != nil { + gatewayRef = kubernetes.NewGatewayRef(*gateway) + } + + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, gatewayRef, weightEqualRoute) // Make sure all test resources are ready kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ConformanceInfraNamespace}) diff --git a/test/e2e/tests/zone_aware_routing.go b/test/e2e/tests/zone_aware_routing.go index 64699c7f5a..1234470400 100644 --- a/test/e2e/tests/zone_aware_routing.go +++ b/test/e2e/tests/zone_aware_routing.go @@ -8,6 +8,7 @@ package tests import ( + "math" "testing" "k8s.io/apimachinery/pkg/types" @@ -28,8 +29,10 @@ var ZoneAwareRoutingTest = suite.ConformanceTest{ Description: "Test Zone Aware Routing is working", Manifests: []string{ "testdata/zone-aware-routing-backendref-enabled.yaml", - "testdata/zone-aware-routing-btp-enabled.yaml", + "testdata/zone-aware-routing-btp-force-local-zone.yaml", + "testdata/zone-aware-routing-btp-no-force-local-zone.yaml", "testdata/zone-aware-routing-deployments.yaml", + "testdata/zone-aware-routing-gateways.yaml", }, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { t.Run("topology aware routing - only local zone should get requests", func(t *testing.T) { @@ -39,12 +42,12 @@ var ZoneAwareRoutingTest = suite.ConformanceTest{ "zone-aware-backend-local": sendRequests, "zone-aware-backend-nonlocal": 0, } - runWeightedBackendTest(t, suite, "topology-aware-routing", "/topology-aware-routing", "zone-aware-backend", expected) + runWeightedBackendTest(t, suite, nil, "topology-aware-routing", "/topology-aware-routing", "zone-aware-backend", expected) }) - t.Run("BackendTrafficPolicy - only local zone should get requests", func(t *testing.T) { + t.Run("BackendTrafficPolicy - ForceLocalZone - only local zone should get requests", func(t *testing.T) { BackendTrafficPolicyMustBeAccepted(t, suite.Client, - types.NamespacedName{Name: "btp-zone-aware", Namespace: "gateway-conformance-infra"}, + types.NamespacedName{Name: "btp-force-local-zone", Namespace: "gateway-conformance-infra"}, suite.ControllerName, gwapiv1a2.ParentReference{ Group: gatewayapi.GroupPtr(gwapiv1.GroupName), @@ -60,7 +63,53 @@ var ZoneAwareRoutingTest = suite.ConformanceTest{ "zone-aware-backend-local": sendRequests, "zone-aware-backend-nonlocal": 0, } - runWeightedBackendTest(t, suite, "btp-zone-aware", "/btp-zone-aware", "zone-aware-backend", expected) + runWeightedBackendTest(t, suite, nil, "btp-force-local-zone", "/btp-force-local-zone", "zone-aware-backend", expected) + }) + t.Run("BackendTrafficPolicy - No ForceLocalZone - local zone should get around 75% of requests", func(t *testing.T) { + BackendTrafficPolicyMustBeAccepted(t, + suite.Client, + types.NamespacedName{Name: "btp-no-force-local-zone", Namespace: "gateway-conformance-infra"}, + suite.ControllerName, + gwapiv1a2.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr("gateway-conformance-infra"), + Name: gwapiv1.ObjectName("same-namespace"), + }, + ) + + // Pods from the backend-local deployment have affinity for the Envoy Proxy pods. + // ForceLocal is not used, and overall we have 4 backend pods, 3 local and 1 non-local. + // Distribution of upstream is 75% local, 25% non-local. Distribution of envoy is 100% local. + // Expect local upstream to get around 75% of traffic. + expected := map[string]int{ + "zone-aware-backend-local": int(math.Round(sendRequests * .75)), + "zone-aware-backend-nonlocal": int(math.Round(sendRequests * .25)), + } + runWeightedBackendTest(t, suite, nil, "btp-no-force-local-zone", "/btp-no-force-local-zone", "zone-aware-backend", expected) + }) + t.Run("BackendTrafficPolicy - No ForceLocalZone - Hardcoded service name in EnvoyProxy - local zone should get around 75% of requests", func(t *testing.T) { + BackendTrafficPolicyMustBeAccepted(t, + suite.Client, + types.NamespacedName{Name: "btp-no-force-local-zone-hardcoded-svc-name", Namespace: "gateway-conformance-infra"}, + suite.ControllerName, + gwapiv1a2.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr("gateway-conformance-infra"), + Name: gwapiv1.ObjectName("zone-aware-routing-gtw"), + }, + ) + + // Pods from the backend-local deployment have affinity for the Envoy Proxy pods. + // ForceLocal is not used, and overall we have 4 backend pods, 3 local and 1 non-local. + // Distribution of upstream is 75% local, 25% non-local. Distribution of envoy is 100% local. + // Expect local upstream to get around 75% of traffic. + expected := map[string]int{ + "zone-aware-backend-local": int(math.Round(sendRequests * .75)), + "zone-aware-backend-nonlocal": int(math.Round(sendRequests * .25)), + } + runWeightedBackendTest(t, suite, &types.NamespacedName{Name: "zone-aware-routing-gtw", Namespace: "gateway-conformance-infra"}, "btp-no-force-local-zone-hardcoded-svc-name", "/btp-no-force-local-zone-hardcoded-svc-name", "zone-aware-backend", expected) }) }, } From e596090adae199138532f3b1e0280dbb0a7ff6eb Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 14 Aug 2025 02:40:00 +0800 Subject: [PATCH 03/27] conformance: update experimental test report (#6782) * conformance: update experimental test report Signed-off-by: zirain * fix version Signed-off-by: zirain --- tools/make/kube.mk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/make/kube.mk b/tools/make/kube.mk index 2cd3aacd5a..b80919f706 100644 --- a/tools/make/kube.mk +++ b/tools/make/kube.mk @@ -318,7 +318,10 @@ run-experimental-conformance: prepare-ip-family ## Run Experimental Gateway API @$(LOG_TARGET) kubectl wait --timeout=$(WAIT_TIMEOUT) -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available kubectl apply -f test/config/gatewayclass.yaml - go test -v -tags experimental ./test/conformance -run TestExperimentalConformance --gateway-class=envoy-gateway --debug=true --organization=envoyproxy --project=envoy-gateway --url=https://github.com/envoyproxy/gateway --version=latest --report-output="$(CONFORMANCE_REPORT_PATH)" --contact=https://github.com/envoyproxy/gateway/blob/main/GOVERNANCE.md + go test -v -tags experimental ./test/conformance -run TestExperimentalConformance --gateway-class=envoy-gateway --debug=true \ + --organization=envoyproxy --project=envoy-gateway --url=https://github.com/envoyproxy/gateway --version=latest \ + --report-output="$(CONFORMANCE_REPORT_PATH)" --contact=https://github.com/envoyproxy/gateway/blob/main/GOVERNANCE.md \ + --mode="$(KUBE_DEPLOY_PROFILE)" --version=$(TAG) .PHONY: delete-cluster delete-cluster: ## Delete kind cluster. From 71390885bdcb69cc01a62dfece7b57ccb0eaa3ba Mon Sep 17 00:00:00 2001 From: Windfarer Date: Wed, 20 Aug 2025 18:52:34 +0800 Subject: [PATCH 04/27] fix(api): image validation regex, support port in repository (#6819) fix: match repository in image with port Signed-off-by: Windfarer Signed-off-by: zirain --- api/v1alpha1/shared_types.go | 2 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 4 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 4 +- test/cel-validation/envoyproxy_test.go | 72 +++++++++++++++++++ test/helm/gateway-crds-helm/all.out.yaml | 4 +- .../envoy-gateway-crds.out.yaml | 4 +- 6 files changed, 81 insertions(+), 9 deletions(-) diff --git a/api/v1alpha1/shared_types.go b/api/v1alpha1/shared_types.go index a16a8019d9..d4bdbcd498 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -231,7 +231,7 @@ type KubernetesContainerSpec struct { // Image specifies the EnvoyProxy container image to be used including a tag, instead of the default image. // This field is mutually exclusive with ImageRepository. // - // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$')",message="Image must include a tag and allowed characters only (e.g., 'repo:tag')." + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$')",message="Image must include a tag and allowed characters only (e.g., 'repo:tag')." // +optional Image *string `json:"image,omitempty"` 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 e5e0dcee63..9a00ee43ff 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 @@ -614,7 +614,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -4459,7 +4459,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. 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 4a8675fdba..3c509d8a03 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -613,7 +613,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -4458,7 +4458,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. diff --git a/test/cel-validation/envoyproxy_test.go b/test/cel-validation/envoyproxy_test.go index 5ec5f57bd3..34b76adc0e 100644 --- a/test/cel-validation/envoyproxy_test.go +++ b/test/cel-validation/envoyproxy_test.go @@ -1669,6 +1669,42 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{}, }, + { + desc: "valid: imageRepository with ip and port", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + ImageRepository: ptr.To("192.168.1.1:8000"), + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "valid: imageRepository with domain and port", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + ImageRepository: ptr.To("registry.com:8000"), + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, { desc: "valid: imageRepository set without tag, image not set", mutate: func(envoy *egv1a1.EnvoyProxy) { @@ -1760,6 +1796,42 @@ func TestEnvoyProxyProvider(t *testing.T) { }, wantErrors: []string{"Image must include a tag and allowed characters only (e.g., 'repo:tag')."}, }, + { + desc: "valid: image with domain and port", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + Image: ptr.To("registry.com:3000/envoy:v1.2.3"), + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "valid: image with ip and port", + mutate: func(envoy *egv1a1.EnvoyProxy) { + envoy.Spec = egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyDeployment: &egv1a1.KubernetesDeploymentSpec{ + Container: &egv1a1.KubernetesContainerSpec{ + Image: ptr.To("127.0.0.1:3000/envoy:v1.2.3"), + }, + }, + }, + }, + } + }, + wantErrors: []string{}, + }, { desc: "invalid: imageRepository contains tag", mutate: func(envoy *egv1a1.EnvoyProxy) { diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 31bdd8db58..44063b6d91 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -24547,7 +24547,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -28392,7 +28392,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. 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 09101b2de0..f912535939 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -7235,7 +7235,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. @@ -11080,7 +11080,7 @@ spec: x-kubernetes-validations: - message: Image must include a tag and allowed characters only (e.g., 'repo:tag'). - rule: self.matches('^[a-zA-Z0-9._/-]+(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') + rule: self.matches('^[a-zA-Z0-9._-]+(:[0-9]+)?(/[a-zA-Z0-9._/-]+)?(:[a-zA-Z0-9._-]+)?(@sha256:[a-z0-9]+)?$') imageRepository: description: |- ImageRepository specifies the container image repository to be used without specifying a tag. From ea6778f0931c6954b8a5158dcb738089dbd709e5 Mon Sep 17 00:00:00 2001 From: Isaac <10012479+jukie@users.noreply.github.com> Date: Mon, 25 Aug 2025 06:00:37 -0600 Subject: [PATCH 05/27] fix: Actually update xdsIR with maxAcceptPerSocketEvent (#6834) * Actually update xdsIR with maxAcceptPerSocketEvent Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> * release note Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> * newline lint Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> --------- Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> Signed-off-by: zirain --- internal/gatewayapi/clienttrafficpolicy.go | 4 + ...ection-max-accept-per-socket-event.in.yaml | 65 ++++ ...ction-max-accept-per-socket-event.out.yaml | 300 ++++++++++++++++++ release-notes/current.yaml | 1 + 4 files changed, 370 insertions(+) create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.in.yaml create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.out.yaml diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index f7727a73ba..0d4baece5b 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -959,6 +959,10 @@ func buildConnection(connection *egv1a1.ClientConnection) (*ir.ClientConnection, irConnection.BufferLimitBytes = ptr.To(uint32(bufferLimit)) } + if connection.MaxAcceptPerSocketEvent != nil { + irConnection.MaxAcceptPerSocketEvent = ptr.To(*connection.MaxAcceptPerSocketEvent) + } + return irConnection, nil } diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.in.yaml new file mode 100644 index 0000000000..e98f57ca58 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.in.yaml @@ -0,0 +1,65 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: default-max-accept + spec: + connection: {} + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: non-default-max-accept + spec: + connection: + maxAcceptPerSocketEvent: 3 + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http-2 +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: disabled-max-accept + spec: + connection: + maxAcceptPerSocketEvent: 0 + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http-3 +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 8081 + allowedRoutes: + namespaces: + from: Same + - name: http-2 + protocol: HTTP + port: 8082 + allowedRoutes: + namespaces: + from: Same + - name: http-3 + protocol: HTTP + port: 8083 + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.out.yaml new file mode 100644 index 0000000000..542c68ee5a --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-connection-max-accept-per-socket-event.out.yaml @@ -0,0 +1,300 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + creationTimestamp: null + name: non-default-max-accept + namespace: envoy-gateway + spec: + connection: + maxAcceptPerSocketEvent: 3 + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http-2 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-2 + 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: ClientTrafficPolicy + metadata: + creationTimestamp: null + name: disabled-max-accept + namespace: envoy-gateway + spec: + connection: + maxAcceptPerSocketEvent: 0 + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: http-3 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-3 + 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: ClientTrafficPolicy + metadata: + creationTimestamp: null + name: default-max-accept + namespace: envoy-gateway + spec: + connection: {} + 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: There are existing ClientTrafficPolicies that are overriding these + sections [http-2 http-3] + reason: Overridden + status: "True" + type: Overridden + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + 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: Same + name: http-1 + port: 8081 + protocol: HTTP + - allowedRoutes: + namespaces: + from: Same + name: http-2 + port: 8082 + protocol: HTTP + - allowedRoutes: + namespaces: + from: Same + name: http-3 + port: 8083 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + 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-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + 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-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + 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-3 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http-1 + ports: + - containerPort: 8081 + name: http-8081 + protocol: HTTP + servicePort: 8081 + - address: null + name: envoy-gateway/gateway-1/http-2 + ports: + - containerPort: 8082 + name: http-8082 + protocol: HTTP + servicePort: 8082 + - address: null + name: envoy-gateway/gateway-1/http-3 + ports: + - containerPort: 8083 + name: http-8083 + protocol: HTTP + servicePort: 8083 + 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 + connection: {} + externalPort: 8081 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-1 + name: envoy-gateway/gateway-1/http-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8081 + - address: 0.0.0.0 + connection: + maxAcceptPerSocketEvent: 3 + externalPort: 8082 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-2 + name: envoy-gateway/gateway-1/http-2 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8082 + - address: 0.0.0.0 + connection: + maxAcceptPerSocketEvent: 0 + externalPort: 8083 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-3 + name: envoy-gateway/gateway-1/http-3 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8083 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/release-notes/current.yaml b/release-notes/current.yaml index ed00bf3e75..b4b22e9d81 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -11,6 +11,7 @@ new features: | bug fixes: | Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. + Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy # Enhancements that improve performance. performance improvements: | From 2e087f50a2ad6350b2acc0359cd5cc57ddc7f2c0 Mon Sep 17 00:00:00 2001 From: qi Date: Wed, 27 Aug 2025 15:34:52 +0800 Subject: [PATCH 06/27] bugfix: fix the topologyInjectorDisabled and the local cluster was not defined (#6847) * bugfix: fix the topologyInjectorDisabled and the local cluster was not defined. Signed-off-by: qicz * fix ut Signed-off-by: qicz * add topology-injector-enabled ut Signed-off-by: qicz * add release note Signed-off-by: qi --------- Signed-off-by: qicz Signed-off-by: qi Signed-off-by: zirain --- internal/xds/bootstrap/bootstrap.yaml.tpl | 2 + internal/xds/bootstrap/bootstrap_test.go | 24 ++++ .../render/topology-injector-disabled.yaml | 84 ++++++++++++++ .../render/topology-injector-enabled.yaml | 103 ++++++++++++++++++ release-notes/current.yaml | 1 + 5 files changed, 214 insertions(+) create mode 100644 internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml create mode 100644 internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml diff --git a/internal/xds/bootstrap/bootstrap.yaml.tpl b/internal/xds/bootstrap/bootstrap.yaml.tpl index f3458b6a66..e14a3d70b6 100644 --- a/internal/xds/bootstrap/bootstrap.yaml.tpl +++ b/internal/xds/bootstrap/bootstrap.yaml.tpl @@ -8,8 +8,10 @@ admin: socket_address: address: {{ .AdminServer.Address }} port_value: {{ .AdminServer.Port }} +{{- if not .TopologyInjectorDisabled }} cluster_manager: local_cluster_name: {{ .ServiceClusterName }} +{{- end }} node: locality: zone: $(ENVOY_SERVICE_ZONE) diff --git a/internal/xds/bootstrap/bootstrap_test.go b/internal/xds/bootstrap/bootstrap_test.go index 2c60748151..23bb6e0401 100644 --- a/internal/xds/bootstrap/bootstrap_test.go +++ b/internal/xds/bootstrap/bootstrap_test.go @@ -180,6 +180,30 @@ func TestGetRenderedBootstrapConfig(t *testing.T) { IPFamily: ptr.To(egv1a1.IPv6), }, }, + { + name: "topology-injector-disabled", + opts: &RenderBootstrapConfigOptions{ + ProxyMetrics: &egv1a1.ProxyMetrics{ + Prometheus: &egv1a1.ProxyPrometheusProvider{ + Disable: true, + }, + }, + SdsConfig: sds, + TopologyInjectorDisabled: true, + }, + }, + { + name: "topology-injector-enabled", + opts: &RenderBootstrapConfigOptions{ + ProxyMetrics: &egv1a1.ProxyMetrics{ + Prometheus: &egv1a1.ProxyPrometheusProvider{ + Disable: true, + }, + }, + SdsConfig: sds, + TopologyInjectorDisabled: false, + }, + }, } for _, tc := range cases { diff --git a/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml b/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml new file mode 100644 index 0000000000..280a6d4ce1 --- /dev/null +++ b/internal/xds/bootstrap/testdata/render/topology-injector-disabled.yaml @@ -0,0 +1,84 @@ +admin: + access_log: + - name: envoy.access_loggers.file + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 19000 +node: + locality: + zone: $(ENVOY_SERVICE_ZONE) +layered_runtime: + layers: + - name: global_config + static_layer: + envoy.restart_features.use_eds_cache_for_ads: true + re2.max_program_size.error_level: 4294967295 + re2.max_program_size.warn_level: 1000 +dynamic_resources: + ads_config: + api_type: DELTA_GRPC + transport_api_version: V3 + grpc_services: + - envoy_grpc: + cluster_name: xds_cluster + set_node_on_first_message_only: true + lds_config: + ads: {} + resource_api_version: V3 + cds_config: + ads: {} + resource_api_version: V3 +static_resources: + clusters: + - connect_timeout: 10s + load_assignment: + cluster_name: xds_cluster + endpoints: + - load_balancing_weight: 1 + lb_endpoints: + - load_balancing_weight: 1 + endpoint: + address: + socket_address: + address: envoy-gateway + port_value: 18000 + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions" + explicit_http_config: + http2_protocol_options: + connection_keepalive: + interval: 30s + timeout: 5s + name: xds_cluster + type: STRICT_DNS + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + common_tls_context: + tls_params: + tls_maximum_protocol_version: TLSv1_3 + tls_certificate_sds_secret_configs: + - name: xds_certificate + sds_config: + path_config_source: + path: /sds/xds-certificate.json + resource_api_version: V3 + validation_context_sds_secret_config: + name: xds_trusted_ca + sds_config: + path_config_source: + path: /sds/xds-trusted-ca.json + resource_api_version: V3 +overload_manager: + refresh_interval: 0.25s + resource_monitors: + - name: "envoy.resource_monitors.global_downstream_max_connections" + typed_config: + "@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig + max_active_downstream_connections: 50000 diff --git a/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml b/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml new file mode 100644 index 0000000000..2635d26d7b --- /dev/null +++ b/internal/xds/bootstrap/testdata/render/topology-injector-enabled.yaml @@ -0,0 +1,103 @@ +admin: + access_log: + - name: envoy.access_loggers.file + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 19000 +cluster_manager: + local_cluster_name: local_cluster +node: + locality: + zone: $(ENVOY_SERVICE_ZONE) +layered_runtime: + layers: + - name: global_config + static_layer: + envoy.restart_features.use_eds_cache_for_ads: true + re2.max_program_size.error_level: 4294967295 + re2.max_program_size.warn_level: 1000 +dynamic_resources: + ads_config: + api_type: DELTA_GRPC + transport_api_version: V3 + grpc_services: + - envoy_grpc: + cluster_name: xds_cluster + set_node_on_first_message_only: true + lds_config: + ads: {} + resource_api_version: V3 + cds_config: + ads: {} + resource_api_version: V3 +static_resources: + clusters: + - connect_timeout: 10s + eds_cluster_config: + eds_config: + ads: {} + resource_api_version: 'V3' + service_name: local_cluster + load_balancing_policy: + policies: + - typed_extension_config: + name: 'envoy.load_balancing_policies.least_request' + typed_config: + '@type': 'type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest' + locality_lb_config: + zone_aware_lb_config: + min_cluster_size: '1' + name: local_cluster + type: EDS + - connect_timeout: 10s + load_assignment: + cluster_name: xds_cluster + endpoints: + - load_balancing_weight: 1 + lb_endpoints: + - load_balancing_weight: 1 + endpoint: + address: + socket_address: + address: envoy-gateway + port_value: 18000 + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": "type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions" + explicit_http_config: + http2_protocol_options: + connection_keepalive: + interval: 30s + timeout: 5s + name: xds_cluster + type: STRICT_DNS + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + common_tls_context: + tls_params: + tls_maximum_protocol_version: TLSv1_3 + tls_certificate_sds_secret_configs: + - name: xds_certificate + sds_config: + path_config_source: + path: /sds/xds-certificate.json + resource_api_version: V3 + validation_context_sds_secret_config: + name: xds_trusted_ca + sds_config: + path_config_source: + path: /sds/xds-trusted-ca.json + resource_api_version: V3 +overload_manager: + refresh_interval: 0.25s + resource_monitors: + - name: "envoy.resource_monitors.global_downstream_max_connections" + typed_config: + "@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig + max_active_downstream_connections: 50000 diff --git a/release-notes/current.yaml b/release-notes/current.yaml index b4b22e9d81..d258388849 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -12,6 +12,7 @@ new features: | bug fixes: | Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy + Fixed the topologyInjectorDisabled and the local cluster was not defined. # Enhancements that improve performance. performance improvements: | From 52ec8a45f7c75852dfd07b36133c6d6d7384236a Mon Sep 17 00:00:00 2001 From: TomerJLevy Date: Thu, 28 Aug 2025 10:25:45 +0200 Subject: [PATCH 07/27] fix(logging): correct log formatting to avoid DPANIC in controller-runtime logger (#6846) * Update filters.go Signed-off-by: TomerJLevy * add release notes Signed-off-by: TomerJLevy --------- Signed-off-by: TomerJLevy Signed-off-by: zirain --- internal/provider/kubernetes/filters.go | 4 ++-- release-notes/current.yaml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/provider/kubernetes/filters.go b/internal/provider/kubernetes/filters.go index 64b3b1e242..5e0ea45d9c 100644 --- a/internal/provider/kubernetes/filters.go +++ b/internal/provider/kubernetes/filters.go @@ -24,7 +24,7 @@ func (r *gatewayAPIReconciler) getExtensionRefFilters(ctx context.Context) ([]un uExtResourceList := &unstructured.UnstructuredList{} uExtResourceList.SetGroupVersionKind(gvk) if err := r.client.List(ctx, uExtResourceList); err != nil { - r.log.Info("no associated resources found for %s", gvk.String()) + r.log.Info("no associated resources found", "GVK", gvk.String()) return nil, fmt.Errorf("failed to list %s: %w", gvk.String(), err) } @@ -57,7 +57,7 @@ func (r *gatewayAPIReconciler) getExtensionBackendResources(ctx context.Context) uExtResourceList := &unstructured.UnstructuredList{} uExtResourceList.SetGroupVersionKind(gvk) if err := r.client.List(ctx, uExtResourceList); err != nil { - r.log.Info("no associated backend resources found for %s", gvk.String()) + r.log.Info("no associated backend resources found", "GVK", gvk.String()) return nil, fmt.Errorf("failed to list %s: %w", gvk.String(), err) } diff --git a/release-notes/current.yaml b/release-notes/current.yaml index d258388849..b8a977f929 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -13,6 +13,7 @@ bug fixes: | Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy Fixed the topologyInjectorDisabled and the local cluster was not defined. + Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. # Enhancements that improve performance. performance improvements: | From 94df7307d5d3e3cc29e5b1cad193a36834ec1cc6 Mon Sep 17 00:00:00 2001 From: TomerJLevy Date: Thu, 28 Aug 2025 20:48:50 +0200 Subject: [PATCH 08/27] 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: zirain --- internal/provider/kubernetes/controller.go | 4 +++- internal/provider/kubernetes/controller_test.go | 10 ++++++++++ release-notes/current.yaml | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index dbf310280f..051d56e2a1 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -256,7 +256,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 bb23b27be9..a19b8a46f0 100644 --- a/internal/provider/kubernetes/controller_test.go +++ b/internal/provider/kubernetes/controller_test.go @@ -1603,6 +1603,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 @@ -1614,6 +1620,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 { diff --git a/release-notes/current.yaml b/release-notes/current.yaml index b8a977f929..fdc5f1d6c2 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -11,9 +11,10 @@ new features: | bug fixes: | Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. - Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy + Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy. Fixed the topologyInjectorDisabled and the local cluster was not defined. Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. + Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. # Enhancements that improve performance. performance improvements: | From e40082e9287f729f2d47abb5f02e42d34d231966 Mon Sep 17 00:00:00 2001 From: qi Date: Fri, 29 Aug 2025 14:06:28 +0800 Subject: [PATCH 09/27] bugfix: the controller cannot read the EnvoyProxy attached gatewayclass only. (#6838) Signed-off-by: zirain --- internal/provider/kubernetes/controller.go | 5 +++ .../provider/kubernetes/controller_test.go | 45 ++++++++++++++++--- release-notes/current.yaml | 1 + 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 051d56e2a1..492bef67b1 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -1483,6 +1483,11 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g // processGatewayParamsRef has been called for this gateway, its EnvoyProxy should exist in resourceTree ep = resourceTree.GetEnvoyProxy(gtw.Namespace, gtw.Spec.Infrastructure.ParametersRef.Name) } + // when gateway's EnvoyProxy is nil and gatewayclass 's EnvoyProxy is not nil + // the specified proxySvcName should get from gatewayclass's EnvoyProxy + if ep == nil && resourceTree.EnvoyProxyForGatewayClass != nil { + ep = resourceTree.EnvoyProxyForGatewayClass + } r.processServiceClusterForGateway(ep, >w, resourceMap) } diff --git a/internal/provider/kubernetes/controller_test.go b/internal/provider/kubernetes/controller_test.go index a19b8a46f0..9d5228761a 100644 --- a/internal/provider/kubernetes/controller_test.go +++ b/internal/provider/kubernetes/controller_test.go @@ -1314,12 +1314,13 @@ func TestProcessServiceClusterForGatewayClass(t *testing.T) { func TestProcessServiceClusterForGateway(t *testing.T) { testCases := []struct { - name string - gateway *gwapiv1.Gateway - envoyProxy *egv1a1.EnvoyProxy - gatewayNamespacedMode bool - expectedSvcName string - expectedSvcNamespace string + name string + gateway *gwapiv1.Gateway + envoyProxy *egv1a1.EnvoyProxy + gatewayClassEnvoyProxy *egv1a1.EnvoyProxy + gatewayNamespacedMode bool + expectedSvcName string + expectedSvcNamespace string }{ { name: "no gateway namespaced mode with no hardcoded service name", @@ -1401,6 +1402,34 @@ func TestProcessServiceClusterForGateway(t *testing.T) { expectedSvcName: "my-gateway-svc", expectedSvcNamespace: "app-namespace", }, + { + name: "no gateway namespaced mode with no hardcoded service name attached gatewayclass", + gateway: &gwapiv1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + Namespace: "app-namespace", + }, + }, + envoyProxy: nil, + gatewayClassEnvoyProxy: &egv1a1.EnvoyProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-gateway", + }, + Spec: egv1a1.EnvoyProxySpec{ + Provider: &egv1a1.EnvoyProxyProvider{ + Type: egv1a1.ProviderTypeKubernetes, + Kubernetes: &egv1a1.EnvoyProxyKubernetesProvider{ + EnvoyService: &egv1a1.KubernetesServiceSpec{ + Name: ptr.To("my-gateway-svc"), + }, + }, + }, + }, + }, + gatewayNamespacedMode: false, + expectedSvcName: "my-gateway-svc", + expectedSvcNamespace: "", + }, } for i := range testCases { @@ -1422,6 +1451,10 @@ func TestProcessServiceClusterForGateway(t *testing.T) { tc.expectedSvcName = proxy.ExpectedResourceHashedName(utils.NamespacedName(tc.gateway).String()) } + if tc.envoyProxy == nil && tc.gatewayClassEnvoyProxy != nil { + tc.envoyProxy = tc.gatewayClassEnvoyProxy + } + r.processServiceClusterForGateway(tc.envoyProxy, tc.gateway, resourceMap) require.Contains(t, resourceMap.allAssociatedBackendRefs, gwapiv1.BackendObjectReference{ diff --git a/release-notes/current.yaml b/release-notes/current.yaml index fdc5f1d6c2..63d168c48b 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -15,6 +15,7 @@ bug fixes: | Fixed the topologyInjectorDisabled and the local cluster was not defined. Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. + Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. # Enhancements that improve performance. performance improvements: | From da4b9ff891de11a6486ed22b41fc75502e4a2e55 Mon Sep 17 00:00:00 2001 From: shahar-h Date: Mon, 8 Sep 2025 20:06:20 +0300 Subject: [PATCH 10/27] chore: fix CVE (#6903) Signed-off-by: Shahar Harari Signed-off-by: zirain --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 11b7a1bd17..24f7ff50f8 100644 --- a/go.mod +++ b/go.mod @@ -434,7 +434,7 @@ require ( github.com/tomarrell/wrapcheck/v2 v2.11.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/uudashr/gocognit v1.2.0 // indirect diff --git a/go.sum b/go.sum index 19ff1864b8..3c8e39b2cd 100644 --- a/go.sum +++ b/go.sum @@ -1007,8 +1007,8 @@ github.com/tsaarni/certyaml v0.10.0 h1:8ZWHO4Zg4VHUf7YblZNju44PcG5M+YtlJawiArYUH github.com/tsaarni/certyaml v0.10.0/go.mod h1:rI1wDTE/VQIglHOyGbjfvqb+5mWTVT5uLFVDDcT1sq8= github.com/tsaarni/x500dn v1.0.0 h1:LvaWTkqRpse4VHBhB5uwf3wytokK4vF9IOyNAEyiA+U= github.com/tsaarni/x500dn v1.0.0/go.mod h1:QaHa3EcUKC4dfCAZmj8+ZRGLKukWgpGv9H3oOCsAbcE= -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 efbb8048b2f22fbacec5c77a7b313fd21b0f8f28 Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Wed, 10 Sep 2025 13:16:03 +0530 Subject: [PATCH 11/27] fix: nil pointer dereference in btp configmap indexer (#6921) Signed-off-by: Rudrakh Panigrahi Signed-off-by: zirain --- internal/provider/kubernetes/controller.go | 2 +- internal/provider/kubernetes/indexers.go | 2 +- .../provider/kubernetes/predicates_test.go | 36 +++++++++++++++++++ release-notes/current.yaml | 1 + 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 492bef67b1..b1637bd63b 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -1267,7 +1267,7 @@ func (r *gatewayAPIReconciler) processBtpConfigMapRefs( ) error { for _, policy := range resourceTree.BackendTrafficPolicies { for _, ro := range policy.Spec.ResponseOverride { - if ro.Response.Body != nil && ro.Response.Body.ValueRef != nil && string(ro.Response.Body.ValueRef.Kind) == resource.KindConfigMap { + if ro.Response != nil && ro.Response.Body != nil && ro.Response.Body.ValueRef != nil && string(ro.Response.Body.ValueRef.Kind) == resource.KindConfigMap { configMap := new(corev1.ConfigMap) err := r.client.Get(ctx, types.NamespacedName{Namespace: policy.Namespace, Name: string(ro.Response.Body.ValueRef.Name)}, diff --git a/internal/provider/kubernetes/indexers.go b/internal/provider/kubernetes/indexers.go index 11418f63da..2b9b5efdb3 100644 --- a/internal/provider/kubernetes/indexers.go +++ b/internal/provider/kubernetes/indexers.go @@ -837,7 +837,7 @@ func configMapBtpIndexFunc(rawObj client.Object) []string { var configMapReferences []string for _, ro := range btp.Spec.ResponseOverride { - if ro.Response.Body != nil && ro.Response.Body.ValueRef != nil { + if ro.Response != nil && ro.Response.Body != nil && ro.Response.Body.ValueRef != nil { if string(ro.Response.Body.ValueRef.Kind) == resource.KindConfigMap { configMapReferences = append(configMapReferences, types.NamespacedName{ diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 61125e80a4..7478febea0 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -286,6 +286,42 @@ func TestValidateConfigMapForReconcile(t *testing.T) { } } +// TestValidateBackendTrafficPolicyForReconcileWithRedirectResponseOverride tests the validateBackendTrafficPolicyForReconcile +// predicate function with a redirect response override. +func TestValidateBackendTrafficPolicyForReconcileWithRedirectResponseOverride(t *testing.T) { + btpWithRedirect := &egv1a1.BackendTrafficPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "response-override", + Namespace: "envoy-gateway-system", + }, + Spec: egv1a1.BackendTrafficPolicySpec{ + ResponseOverride: []*egv1a1.ResponseOverride{ + { + Match: egv1a1.CustomResponseMatch{ + StatusCodes: []egv1a1.StatusCodeMatch{ + { + Type: &[]egv1a1.StatusCodeValueType{egv1a1.StatusCodeValueTypeRange}[0], + Range: &egv1a1.StatusCodeRange{ + Start: 500, + End: 511, + }, + }, + }, + }, + // Using redirect instead of response causes ro.Response to be nil + Redirect: &egv1a1.CustomRedirect{ + Hostname: &[]gwapiv1.PreciseHostname{"custom-errors.example.com"}[0], + StatusCode: &[]int{302}[0], + Scheme: &[]string{"https"}[0], + }, + }, + }, + }, + } + result := configMapBtpIndexFunc(btpWithRedirect) + require.Empty(t, result) +} + // TestValidateSecretForReconcile tests the validateSecretForReconcile // predicate function. func TestValidateSecretForReconcile(t *testing.T) { diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 63d168c48b..85ee7ccf57 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -16,6 +16,7 @@ bug fixes: | Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. + Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. # Enhancements that improve performance. performance improvements: | From dc98024ebbef8eea18f0adc369da1cc5d4b68105 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Wed, 10 Sep 2025 06:45:26 -0700 Subject: [PATCH 12/27] improve targetRef selection for targetSelectors (#6917) * improve targetRef selection for targetSelectors * only select refs in the same namespace as the policy Signed-off-by: Arko Dasgupta * fix lint Signed-off-by: Arko Dasgupta --------- Signed-off-by: Arko Dasgupta Signed-off-by: zirain --- internal/gatewayapi/backendtrafficpolicy.go | 6 +- internal/gatewayapi/clienttrafficpolicy.go | 2 +- internal/gatewayapi/envoyextensionpolicy.go | 4 +- internal/gatewayapi/extensionserverpolicy.go | 2 +- internal/gatewayapi/helpers.go | 7 +- internal/gatewayapi/helpers_test.go | 2 +- internal/gatewayapi/securitypolicy.go | 8 +- ...cy-multiple-targets-targetselector.in.yaml | 128 ++++++++ ...y-multiple-targets-targetselector.out.yaml | 278 ++++++++++++++++++ 9 files changed, 424 insertions(+), 13 deletions(-) create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.in.yaml create mode 100644 internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.out.yaml diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 494ef2d3d4..8d137223f9 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -77,7 +77,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources // TODO: This loop is similar to the one 'Process the policies targeting Gateways', we may want to // merge them into one if possible. for _, currPolicy := range backendTrafficPolicies { - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind == resource.KindGateway { // Check if the gateway exists @@ -104,7 +104,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources // Process the policies targeting xRoutes for _, currPolicy := range backendTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind != resource.KindGateway { policy, found := handledPolicies[policyName] @@ -232,7 +232,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources // Process the policies targeting Gateways for _, currPolicy := range backendTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind == resource.KindGateway { policy, found := handledPolicies[policyName] diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 0d4baece5b..8929d60268 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -163,7 +163,7 @@ func (t *Translator) ProcessClientTrafficPolicies( // Policy with no section set (targeting all sections) for _, currPolicy := range clientTrafficPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if !hasSectionName(&currTarget) { diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index c1e23b2a50..8c4c5e0bec 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -73,7 +73,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv // Process the policies targeting xRoutes for _, currPolicy := range envoyExtensionPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind != resource.KindGateway { policy, found := handledPolicies[policyName] @@ -147,7 +147,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv // Process the policies targeting Gateways for _, currPolicy := range envoyExtensionPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind == resource.KindGateway { policy, found := handledPolicies[policyName] diff --git a/internal/gatewayapi/extensionserverpolicy.go b/internal/gatewayapi/extensionserverpolicy.go index d10fb8116a..b80c838faf 100644 --- a/internal/gatewayapi/extensionserverpolicy.go +++ b/internal/gatewayapi/extensionserverpolicy.go @@ -103,7 +103,7 @@ func extractTargetRefs(policy *unstructured.Unstructured, gateways []*GatewayCon if err := json.Unmarshal(specAsJSON, &targetRefs); err != nil { return nil, fmt.Errorf("no targets found for the policy") } - ret := getPolicyTargetRefs(targetRefs, gateways) + ret := getPolicyTargetRefs(targetRefs, gateways, policy.GetNamespace()) if len(ret) == 0 { return nil, fmt.Errorf("no targets found for the policy") } diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 2126a93ce8..efa9659df4 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -556,7 +556,7 @@ func selectorFromTargetSelector(selector egv1a1.TargetSelector) labels.Selector return l } -func getPolicyTargetRefs[T client.Object](policy egv1a1.PolicyTargetReferences, potentialTargets []T) []gwapiv1a2.LocalPolicyTargetReferenceWithSectionName { +func getPolicyTargetRefs[T client.Object](policy egv1a1.PolicyTargetReferences, potentialTargets []T, policyNamespace string) []gwapiv1a2.LocalPolicyTargetReferenceWithSectionName { dedup := sets.New[targetRefWithTimestamp]() for _, currSelector := range policy.TargetSelectors { labelSelector := selectorFromTargetSelector(currSelector) @@ -567,6 +567,11 @@ func getPolicyTargetRefs[T client.Object](policy egv1a1.PolicyTargetReferences, continue } + // Skip objects not in the same namespace as the policy + if obj.GetNamespace() != policyNamespace { + continue + } + if labelSelector.Matches(labels.Set(obj.GetLabels())) { dedup.Insert(targetRefWithTimestamp{ CreationTimestamp: obj.GetCreationTimestamp(), diff --git a/internal/gatewayapi/helpers_test.go b/internal/gatewayapi/helpers_test.go index 72df6c66c9..228daed0d5 100644 --- a/internal/gatewayapi/helpers_test.go +++ b/internal/gatewayapi/helpers_test.go @@ -581,7 +581,7 @@ func TestGetPolicyTargetRefs(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - results := getPolicyTargetRefs(tc.policy, tc.targets) + results := getPolicyTargetRefs(tc.policy, tc.targets, "default") require.ElementsMatch(t, results, tc.results) }) } diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 86686d15fd..00926a8a56 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -92,7 +92,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security // Process the policies targeting RouteRules for _, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind != resource.KindGateway && currTarget.SectionName != nil { policy, found := handledPolicies[policyName] @@ -110,7 +110,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security // Process the policies targeting xRoutes for _, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind != resource.KindGateway && currTarget.SectionName == nil { policy, found := handledPolicies[policyName] @@ -128,7 +128,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security // Process the policies targeting Listeners for _, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind == resource.KindGateway && currTarget.SectionName != nil { policy, found := handledPolicies[policyName] @@ -146,7 +146,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security // Process the policies targeting Gateways for _, currPolicy := range securityPolicies { policyName := utils.NamespacedName(currPolicy) - targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways) + targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways, currPolicy.Namespace) for _, currTarget := range targetRefs { if currTarget.Kind == resource.KindGateway && currTarget.SectionName == nil { policy, found := handledPolicies[policyName] diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.in.yaml new file mode 100644 index 0000000000..9ce7c95d67 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.in.yaml @@ -0,0 +1,128 @@ +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 + labels: + app: web-service + 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: envoy-gateway + name: httproute + labels: + app: web-service + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-2 + namespace: envoy-gateway + port: 8080 +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + namespace: envoy-gateway + name: policy-for-route-in-envoy-gateway-ns + spec: + targetSelectors: + - group: gateway.networking.k8s.io + kind: HTTPRoute + matchLabels: + app: web-service + useClientProtocol: true +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: default + name: service-1 + spec: + ports: + - port: 8080 + name: http + protocol: TCP +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-2 + spec: + ports: + - port: 8080 + name: http + protocol: TCP +endpointSlices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-service-1 + namespace: default + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 8.8.8.8 + conditions: + ready: true +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-service-2 + namespace: envoy-gateway + labels: + kubernetes.io/service-name: service-2 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 8.8.8.8 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.out.yaml new file mode 100644 index 0000000000..8387973181 --- /dev/null +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-multiple-targets-targetselector.out.yaml @@ -0,0 +1,278 @@ +backendTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: BackendTrafficPolicy + metadata: + creationTimestamp: null + name: policy-for-route-in-envoy-gateway-ns + namespace: envoy-gateway + spec: + targetSelectors: + - group: gateway.networking.k8s.io + kind: HTTPRoute + matchLabels: + app: web-service + useClientProtocol: true + 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 +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: 2 + 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 + labels: + app: web-service + name: httproute + 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 + labels: + app: web-service + name: httproute + namespace: envoy-gateway + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-2 + namespace: envoy-gateway + 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 + namespace: default + name: httproute/default/httproute/rule/0 + settings: + - addressType: IP + endpoints: + - host: 8.8.8.8 + port: 8080 + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute + namespace: default + name: httproute/default/httproute/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + - destination: + metadata: + kind: HTTPRoute + name: httproute + namespace: envoy-gateway + name: httproute/envoy-gateway/httproute/rule/0 + settings: + - addressType: IP + endpoints: + - host: 8.8.8.8 + port: 8080 + metadata: + kind: Service + name: service-2 + namespace: envoy-gateway + sectionName: "8080" + name: httproute/envoy-gateway/httproute/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute + namespace: envoy-gateway + name: httproute/envoy-gateway/httproute/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + traffic: {} + useClientProtocol: true + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 From 1a8816297cceb1aebe8dbb6ce319055154312932 Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Thu, 11 Sep 2025 06:33:56 +0530 Subject: [PATCH 13/27] fix: suppress lua validation logs (#6929) Signed-off-by: Rudrakh Panigrahi Signed-off-by: zirain --- internal/gatewayapi/envoyextensionpolicy.go | 9 ++---- .../gatewayapi/luavalidator/lua_validator.go | 30 +++++++++++++++---- .../luavalidator/lua_validator_test.go | 26 ++++++++++++---- release-notes/current.yaml | 1 + 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 8c4c5e0bec..a3320f97da 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -466,7 +466,6 @@ func (t *Translator) buildLua( envoyProxy *egv1a1.EnvoyProxy, ) (*ir.Lua, error) { var luaCode *string - var luaValidation egv1a1.LuaValidation var err error if lua.Type == egv1a1.LuaValueTypeValueRef { luaCode, err = getLuaBodyFromLocalObjectReference(lua.ValueRef, resources, policy.Namespace) @@ -476,12 +475,8 @@ func (t *Translator) buildLua( if err != nil { return nil, err } - if envoyProxy != nil && envoyProxy.Spec.LuaValidation != nil { - luaValidation = *envoyProxy.Spec.LuaValidation - } else { - luaValidation = egv1a1.LuaValidationStrict - } - if err = luavalidator.NewLuaValidator(*luaCode, luaValidation).Validate(); err != nil { + + if err = luavalidator.NewLuaValidator(*luaCode, envoyProxy).Validate(); err != nil { return nil, fmt.Errorf("validation failed for lua body in policy with name %v: %w", name, err) } return &ir.Lua{ diff --git a/internal/gatewayapi/luavalidator/lua_validator.go b/internal/gatewayapi/luavalidator/lua_validator.go index d3628f51bc..1c103ee175 100644 --- a/internal/gatewayapi/luavalidator/lua_validator.go +++ b/internal/gatewayapi/luavalidator/lua_validator.go @@ -30,14 +30,14 @@ var mockData []byte // Validation strictness is controlled by the validation field type LuaValidator struct { code string - validation egv1a1.LuaValidation + envoyProxy *egv1a1.EnvoyProxy } // NewLuaValidator returns a LuaValidator for user provided Lua code -func NewLuaValidator(code string, validation egv1a1.LuaValidation) *LuaValidator { +func NewLuaValidator(code string, envoyProxy *egv1a1.EnvoyProxy) *LuaValidator { return &LuaValidator{ code: code, - validation: validation, + envoyProxy: envoyProxy, } } @@ -61,7 +61,7 @@ func (l *LuaValidator) Validate() error { // validate runs the validation on given code func (l *LuaValidator) validate(code string) error { - switch l.validation { + switch l.getLuaValidation() { case egv1a1.LuaValidationSyntax: return l.loadLua(code) case egv1a1.LuaValidationDisabled: @@ -71,10 +71,28 @@ func (l *LuaValidator) validate(code string) error { } } +// getLuaValidation returns the Lua validation level, defaulting to strict if not configured +func (l *LuaValidator) getLuaValidation() egv1a1.LuaValidation { + if l.envoyProxy != nil && l.envoyProxy.Spec.LuaValidation != nil { + return *l.envoyProxy.Spec.LuaValidation + } + return egv1a1.LuaValidationStrict +} + +// newLuaState creates a new Lua state with global settings applied +func (l *LuaValidator) newLuaState() *lua.LState { + L := lua.NewState() + // Suppress all print statements + L.SetGlobal("print", L.NewFunction(func(L *lua.LState) int { + return 0 + })) + return L +} + // runLua interprets and runs the provided Lua code in runtime using gopher-lua // Refer: https://github.com/yuin/gopher-lua?tab=readme-ov-file#differences-between-lua-and-gopherlua func (l *LuaValidator) runLua(code string) error { - L := lua.NewState() + L := l.newLuaState() defer L.Close() if err := L.DoString(code); err != nil { return err @@ -85,7 +103,7 @@ func (l *LuaValidator) runLua(code string) error { // loadLua loads the Lua code into the Lua state, does not run it // This is used to check for syntax errors in the Lua code func (l *LuaValidator) loadLua(code string) error { - L := lua.NewState() + L := l.newLuaState() defer L.Close() if _, err := L.LoadString(code); err != nil { return err diff --git a/internal/gatewayapi/luavalidator/lua_validator_test.go b/internal/gatewayapi/luavalidator/lua_validator_test.go index fb5ca5604f..0b57c27420 100644 --- a/internal/gatewayapi/luavalidator/lua_validator_test.go +++ b/internal/gatewayapi/luavalidator/lua_validator_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" + "k8s.io/utils/ptr" + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" ) @@ -16,7 +18,7 @@ func Test_Validate(t *testing.T) { type args struct { name string code string - validation egv1a1.LuaValidation + proxy *egv1a1.EnvoyProxy expectedErrSubstring string } tests := []args{ @@ -28,7 +30,7 @@ func Test_Validate(t *testing.T) { { name: "logInfo: envoy_on_response", code: `function envoy_on_response(response_handle) - response_handle:logInfo("Goodbye.") + response_handle:logInfo("This log should not be printed.") end`, expectedErrSubstring: "", }, @@ -156,7 +158,11 @@ func Test_Validate(t *testing.T) { code: `function envoy_on_request(request_handle) request_handle:unknownApi() end`, - validation: egv1a1.LuaValidationSyntax, + proxy: &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + LuaValidation: ptr.To(egv1a1.LuaValidationSyntax), + }, + }, expectedErrSubstring: "", }, { @@ -173,7 +179,11 @@ func Test_Validate(t *testing.T) { last:setBytes("Not Found") end`, - validation: egv1a1.LuaValidationSyntax, + proxy: &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + LuaValidation: ptr.To(egv1a1.LuaValidationSyntax), + }, + }, expectedErrSubstring: " at EOF: syntax error", }, { @@ -190,13 +200,17 @@ func Test_Validate(t *testing.T) { last:setBytes("Not Found") end`, - validation: egv1a1.LuaValidationDisabled, + proxy: &egv1a1.EnvoyProxy{ + Spec: egv1a1.EnvoyProxySpec{ + LuaValidation: ptr.To(egv1a1.LuaValidationDisabled), + }, + }, expectedErrSubstring: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := NewLuaValidator(tt.code, tt.validation) + l := NewLuaValidator(tt.code, tt.proxy) if err := l.Validate(); err != nil && tt.expectedErrSubstring == "" { t.Errorf("Unexpected error: %v", err) } else if err != nil && !strings.Contains(err.Error(), tt.expectedErrSubstring) { diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 85ee7ccf57..2e20ecdf80 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -17,6 +17,7 @@ bug fixes: | Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. + Fixed Lua validator log level to be suppressed by default. # Enhancements that improve performance. performance improvements: | From d35cfa2ddba95633e63c9aea2dcaa20a79be665b Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Wed, 10 Sep 2025 20:18:42 -0700 Subject: [PATCH 14/27] 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: zirain --- 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 d4bdbcd498..de0e778577 100644 --- a/api/v1alpha1/shared_types.go +++ b/api/v1alpha1/shared_types.go @@ -516,8 +516,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 1bec67423c..2adaa4916f 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 @@ -320,8 +320,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 @@ -1676,8 +1675,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 cfb084ddca..2c4a3d8a2b 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 @@ -417,8 +417,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -928,8 +927,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 9a00ee43ff..1d3fe914b7 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 @@ -10977,8 +10977,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11537,8 +11536,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12090,8 +12088,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12650,8 +12647,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13307,8 +13303,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13842,8 +13837,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14424,8 +14418,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14955,8 +14948,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 9a53734974..129e850fe7 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 @@ -922,8 +922,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1442,8 +1441,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1931,8 +1929,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2451,8 +2448,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3135,8 +3131,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3668,8 +3663,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4399,8 +4393,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4919,8 +4912,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 b81d397d62..aee0777332 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml @@ -319,8 +319,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 @@ -1675,8 +1674,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 aeed98b113..c84cf5b1e3 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/crds/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 @@ -927,8 +926,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 3c509d8a03..d8f4e217bd 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -10976,8 +10976,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -11536,8 +11535,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12089,8 +12087,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -12649,8 +12646,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13306,8 +13302,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -13841,8 +13836,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14423,8 +14417,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -14954,8 +14947,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 090a8f8e2c..caa51f7388 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -921,8 +921,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1441,8 +1440,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -1930,8 +1928,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -2450,8 +2447,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3134,8 +3130,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -3667,8 +3662,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4398,8 +4392,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -4918,8 +4911,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 17986a5ae7..2f500539d4 100644 --- a/test/cel-validation/backendtrafficpolicy_test.go +++ b/test/cel-validation/backendtrafficpolicy_test.go @@ -943,7 +943,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 44063b6d91..23b90b5544 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -17963,8 +17963,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 @@ -19319,8 +19318,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 @@ -21864,8 +21862,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -22375,8 +22372,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -34910,8 +34906,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -35470,8 +35465,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -36023,8 +36017,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -36583,8 +36576,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -37240,8 +37232,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -37775,8 +37766,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -38357,8 +38347,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -38888,8 +38877,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -40317,8 +40305,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -40837,8 +40824,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -41326,8 +41312,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -41846,8 +41831,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -42530,8 +42514,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -43063,8 +43046,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -43794,8 +43776,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -44314,8 +44295,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 f912535939..aafbd783ac 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -651,8 +651,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 @@ -2007,8 +2006,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 @@ -4552,8 +4550,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -5063,8 +5060,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -17598,8 +17594,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -18158,8 +18153,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -18711,8 +18705,7 @@ spec: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -19271,8 +19264,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -19928,8 +19920,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -20463,8 +20454,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -21045,8 +21035,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -21576,8 +21565,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -23005,8 +22993,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -23525,8 +23512,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -24014,8 +24000,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -24534,8 +24519,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -25218,8 +25202,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -25751,8 +25734,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -26482,8 +26464,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array @@ -27002,8 +26983,7 @@ spec: items: description: HTTPStatus defines the http status code. - exclusiveMaximum: true - maximum: 600 + maximum: 599 minimum: 100 type: integer type: array From a71027f9c24ca38f0801a25e055fcb3319549c68 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Wed, 10 Sep 2025 20:22:59 -0700 Subject: [PATCH 15/27] fix: rm Strict SameSite default (#6941) * by default it should be unset which implies `Lax` Relates to https://github.com/envoyproxy/gateway/pull/6347 Signed-off-by: Arko Dasgupta Signed-off-by: zirain --- api/v1alpha1/oidc_types.go | 1 - .../generated/gateway.envoyproxy.io_securitypolicies.yaml | 1 - .../crds/generated/gateway.envoyproxy.io_securitypolicies.yaml | 1 - site/content/en/latest/api/extension_types.md | 2 +- test/helm/gateway-crds-helm/all.out.yaml | 1 - test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml | 1 - 6 files changed, 1 insertion(+), 6 deletions(-) diff --git a/api/v1alpha1/oidc_types.go b/api/v1alpha1/oidc_types.go index cd3e4b72d1..23f84ae2b9 100644 --- a/api/v1alpha1/oidc_types.go +++ b/api/v1alpha1/oidc_types.go @@ -232,6 +232,5 @@ const ( type OIDCCookieConfig struct { // +optional // +kubebuilder:validation:Enum=Lax;Strict;None - // +kubebuilder:default=Strict SameSite *string `json:"sameSite,omitempty"` } 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 129e850fe7..6934fd3cd5 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 @@ -3903,7 +3903,6 @@ spec: By default, its unset. properties: sameSite: - default: Strict enum: - Lax - Strict 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 caa51f7388..19fbc299b5 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3902,7 +3902,6 @@ spec: By default, its unset. properties: sameSite: - default: Strict enum: - Lax - Strict diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 25a018542f..018a5f6e20 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -3351,7 +3351,7 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `sameSite` | _string_ | false | Strict | | +| `sameSite` | _string_ | false | | | #### OIDCCookieNames diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 23b90b5544..b0f287a1f7 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -43286,7 +43286,6 @@ spec: By default, its unset. properties: sameSite: - default: Strict enum: - Lax - Strict 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 aafbd783ac..494471658b 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -25974,7 +25974,6 @@ spec: By default, its unset. properties: sameSite: - default: Strict enum: - Lax - Strict From 22482cf3876257fc4de160c56eb4e80dd732510d Mon Sep 17 00:00:00 2001 From: Isaac <10012479+jukie@users.noreply.github.com> Date: Thu, 11 Sep 2025 00:48:26 -0600 Subject: [PATCH 16/27] Optimize pod cache (#6936) * Optimize pod cache Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> * release note Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> * Remove retry Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> * cleanup Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> --------- Signed-off-by: jukie <10012479+Jukie@users.noreply.github.com> Signed-off-by: Isaac <10012479+jukie@users.noreply.github.com> Co-authored-by: zirain Signed-off-by: zirain --- internal/provider/kubernetes/kubernetes.go | 20 ++++++++++++++++--- .../provider/kubernetes/topology_injector.go | 16 +++++++++------ release-notes/current.yaml | 1 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/internal/provider/kubernetes/kubernetes.go b/internal/provider/kubernetes/kubernetes.go index b99a486d3f..57084b84a4 100644 --- a/internal/provider/kubernetes/kubernetes.go +++ b/internal/provider/kubernetes/kubernetes.go @@ -10,6 +10,8 @@ import ( "fmt" "time" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/rest" "k8s.io/klog/v2" "k8s.io/utils/ptr" @@ -26,6 +28,7 @@ import ( egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/envoygateway" ec "github.com/envoyproxy/gateway/internal/envoygateway/config" + "github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/proxy" "github.com/envoyproxy/gateway/internal/message" ) @@ -112,6 +115,16 @@ func New(ctx context.Context, restCfg *rest.Config, svrCfg *ec.Server, resources mgrOpts.Cache.SyncPeriod = ptr.To(csp) } + // Limit the cache to only Envoy proxy Pods to reduce memory and sync churn. + // ProxyTopologyInjector is the only component that interacts with Pods. + if mgrOpts.Cache.ByObject == nil { + mgrOpts.Cache.ByObject = map[client.Object]cache.ByObject{} + } + + mgrOpts.Cache.ByObject[&corev1.Pod{}] = cache.ByObject{ + Label: labels.SelectorFromSet(proxy.EnvoyAppLabel()), + } + if svrCfg.EnvoyGateway.NamespaceMode() { mgrOpts.Cache.DefaultNamespaces = make(map[string]cache.Config) for _, watchNS := range svrCfg.EnvoyGateway.Provider.Kubernetes.Watch.Namespaces { @@ -134,9 +147,10 @@ func New(ctx context.Context, restCfg *rest.Config, svrCfg *ec.Server, resources if svrCfg.EnvoyGateway.Provider.Kubernetes.TopologyInjector == nil || !ptr.Deref(svrCfg.EnvoyGateway.Provider.Kubernetes.TopologyInjector.Disable, false) { mgr.GetWebhookServer().Register("/inject-pod-topology", &webhook.Admission{ Handler: &ProxyTopologyInjector{ - Client: mgr.GetClient(), - Logger: svrCfg.Logger.WithName("proxy-topology-injector"), - Decoder: admission.NewDecoder(mgr.GetScheme()), + Client: mgr.GetClient(), + APIReader: mgr.GetAPIReader(), + Logger: svrCfg.Logger.WithName("proxy-topology-injector"), + Decoder: admission.NewDecoder(mgr.GetScheme()), }, }) } diff --git a/internal/provider/kubernetes/topology_injector.go b/internal/provider/kubernetes/topology_injector.go index 9a4edea229..c928dfe2f7 100644 --- a/internal/provider/kubernetes/topology_injector.go +++ b/internal/provider/kubernetes/topology_injector.go @@ -22,9 +22,9 @@ import ( type ProxyTopologyInjector struct { client.Client - Decoder admission.Decoder - - Logger logging.Logger + APIReader client.Reader + Decoder admission.Decoder + Logger logging.Logger } func (m *ProxyTopologyInjector) Handle(ctx context.Context, req admission.Request) admission.Response { @@ -50,9 +50,13 @@ func (m *ProxyTopologyInjector) Handle(ctx context.Context, req admission.Reques pod := &corev1.Pod{} if err := m.Get(ctx, podName, pod); err != nil { - logger.Error(err, "get pod failed", "pod", podName.String()) - topologyInjectorEventsTotal.WithFailure(metrics.ReasonError).Increment() - return admission.Allowed("internal error, skipped") + // Cache isn't guaranteed to be updated yet so if m.Get() fails + // try getting the pod from API server directly. + if err = m.APIReader.Get(ctx, podName, pod); err != nil { + logger.Error(err, "get pod failed", "pod", podName.String()) + topologyInjectorEventsTotal.WithFailure(metrics.ReasonError).Increment() + return admission.Allowed("internal error, skipped") + } } // Skip non-proxy pods diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 2e20ecdf80..f659471105 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -18,6 +18,7 @@ bug fixes: | Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. Fixed Lua validator log level to be suppressed by default. + Fixed ProxyTopologyInjector cache sync race condition that caused injection failures # Enhancements that improve performance. performance improvements: | From b020ae96027ada97ab4fc0fb6451832bf56b269f Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Fri, 12 Sep 2025 04:15:33 -0700 Subject: [PATCH 17/27] reduce DeepCopy in gateway-api layer (#6940) * reduce deep copy in gateway-api layer * also fixed the DeepCopy implementation for ControllerResources which was performing a Shallow Copy resulting it lack of isolation b/w provider and gateway-api layer Relates to https://github.com/envoyproxy/gateway/issues/6919 Signed-off-by: Arko Dasgupta * fix lint Signed-off-by: Arko Dasgupta --------- Signed-off-by: Arko Dasgupta Signed-off-by: zirain --- internal/gatewayapi/backend.go | 2 - internal/gatewayapi/backendtrafficpolicy.go | 6 +- internal/gatewayapi/clienttrafficpolicy.go | 4 +- internal/gatewayapi/envoyextensionpolicy.go | 4 +- internal/gatewayapi/envoypatchpolicy.go | 2 +- internal/gatewayapi/extensionserverpolicy.go | 2 +- internal/gatewayapi/resource/resource.go | 6 +- internal/gatewayapi/route.go | 25 +- internal/gatewayapi/securitypolicy.go | 8 +- .../extensionpolicy-tcp-listener.out.yaml | 29 ++ .../extensionpolicy-udp-listener.out.yaml | 29 ++ ...ionpolicy-with-valid-target-array.out.yaml | 52 +++ ...extensionpolicy-with-valid-target.out.yaml | 29 ++ internal/gatewayapi/translator.go | 2 +- test/gobench/translate_test.go | 359 ++++++++++++++++++ 15 files changed, 522 insertions(+), 37 deletions(-) create mode 100644 test/gobench/translate_test.go diff --git a/internal/gatewayapi/backend.go b/internal/gatewayapi/backend.go index 300bac024a..d1772428a0 100644 --- a/internal/gatewayapi/backend.go +++ b/internal/gatewayapi/backend.go @@ -22,8 +22,6 @@ import ( func (t *Translator) ProcessBackends(backends []*egv1a1.Backend, backendTLSPolicies []*gwapiv1a3.BackendTLSPolicy) []*egv1a1.Backend { var res []*egv1a1.Backend for _, backend := range backends { - backend := backend.DeepCopy() - // Ensure Backends are enabled if !t.BackendEnabled { status.UpdateBackendStatusAcceptedCondition(backend, false, diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 8d137223f9..c62d21bc9c 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -109,7 +109,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources if currTarget.Kind != resource.KindGateway { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -237,7 +237,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources if currTarget.Kind == resource.KindGateway { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -545,7 +545,7 @@ func applyTrafficFeatureToRoute(route RouteContext, func mergeBackendTrafficPolicy(routePolicy, gwPolicy *egv1a1.BackendTrafficPolicy) (*egv1a1.BackendTrafficPolicy, error) { if routePolicy.Spec.MergeType == nil || gwPolicy == nil { - return routePolicy.DeepCopy(), nil + return routePolicy, nil } return utils.Merge[*egv1a1.BackendTrafficPolicy](gwPolicy, routePolicy, *routePolicy.Spec.MergeType) diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 8929d60268..6b214bdf0f 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -72,7 +72,7 @@ func (t *Translator) ProcessClientTrafficPolicies( if hasSectionName(&currTarget) { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -169,7 +169,7 @@ func (t *Translator) ProcessClientTrafficPolicies( policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy res = append(res, policy) handledPolicies[policyName] = policy } diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index a3320f97da..061898b435 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -78,7 +78,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv if currTarget.Kind != resource.KindGateway { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy res = append(res, policy) handledPolicies[policyName] = policy } @@ -152,7 +152,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv if currTarget.Kind == resource.KindGateway { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy res = append(res, policy) handledPolicies[policyName] = policy } diff --git a/internal/gatewayapi/envoypatchpolicy.go b/internal/gatewayapi/envoypatchpolicy.go index 310efc02fa..2b6f0f39c5 100644 --- a/internal/gatewayapi/envoypatchpolicy.go +++ b/internal/gatewayapi/envoypatchpolicy.go @@ -23,7 +23,7 @@ func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.Envo for _, policy := range envoyPatchPolicies { var ( - policy = policy.DeepCopy() + policy = policy ancestorRefs []gwapiv1a2.ParentReference resolveErr *status.PolicyResolveError targetKind string diff --git a/internal/gatewayapi/extensionserverpolicy.go b/internal/gatewayapi/extensionserverpolicy.go index b80c838faf..bb65606c06 100644 --- a/internal/gatewayapi/extensionserverpolicy.go +++ b/internal/gatewayapi/extensionserverpolicy.go @@ -40,7 +40,7 @@ func (t *Translator) ProcessExtensionServerPolicies(policies []unstructured.Unst // Process the policies targeting Gateways. Only update the policy status if it was accepted. // A policy is considered accepted if at least one targetRef contained inside matched a listener. for policyIndex, policy := range policies { - policy := policy.DeepCopy() + policy := &policy var policyStatus gwapiv1a2.PolicyStatus accepted := false targetRefs, err := extractTargetRefs(policy, gateways) diff --git a/internal/gatewayapi/resource/resource.go b/internal/gatewayapi/resource/resource.go index 623f8357c1..7e08e648ba 100644 --- a/internal/gatewayapi/resource/resource.go +++ b/internal/gatewayapi/resource/resource.go @@ -221,7 +221,11 @@ func (c *ControllerResources) DeepCopy() *ControllerResources { return nil } out := make(ControllerResources, len(*c)) - copy(out, *c) + for i, res := range *c { + if res != nil { + out[i] = res.DeepCopy() + } + } return &out } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 35b114b980..7a1acc8703 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -60,10 +60,7 @@ func (t *Translator) ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways if h == nil { panic("received nil httproute") } - httpRoute := &HTTPRouteContext{ - GatewayControllerName: t.GatewayControllerName, - HTTPRoute: h.DeepCopy(), - } + httpRoute := &HTTPRouteContext{HTTPRoute: h} // Find out if this route attaches to one of our Gateway's listeners, // and if so, get the list of listeners that allow it to attach for each @@ -90,10 +87,7 @@ func (t *Translator) ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways if g == nil { panic("received nil grpcroute") } - grpcRoute := &GRPCRouteContext{ - GatewayControllerName: t.GatewayControllerName, - GRPCRoute: g.DeepCopy(), - } + grpcRoute := &GRPCRouteContext{GRPCRoute: g} // Find out if this route attaches to one of our Gateway's listeners, // and if so, get the list of listeners that allow it to attach for each @@ -922,10 +916,7 @@ func (t *Translator) ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways if tls == nil { panic("received nil tlsroute") } - tlsRoute := &TLSRouteContext{ - GatewayControllerName: t.GatewayControllerName, - TLSRoute: tls.DeepCopy(), - } + tlsRoute := &TLSRouteContext{TLSRoute: tls} // Find out if this route attaches to one of our Gateway's listeners, // and if so, get the list of listeners that allow it to attach for each @@ -1069,10 +1060,7 @@ func (t *Translator) ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways if u == nil { panic("received nil udproute") } - udpRoute := &UDPRouteContext{ - GatewayControllerName: t.GatewayControllerName, - UDPRoute: u.DeepCopy(), - } + udpRoute := &UDPRouteContext{UDPRoute: u} // Find out if this route attaches to one of our Gateway's listeners, // and if so, get the list of listeners that allow it to attach for each @@ -1220,10 +1208,7 @@ func (t *Translator) ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways if tcp == nil { panic("received nil tcproute") } - tcpRoute := &TCPRouteContext{ - GatewayControllerName: t.GatewayControllerName, - TCPRoute: tcp.DeepCopy(), - } + tcpRoute := &TCPRouteContext{TCPRoute: tcp} // Find out if this route attaches to one of our Gateway's listeners, // and if so, get the list of listeners that allow it to attach for each diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 00926a8a56..7fc9a3286b 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -97,7 +97,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security if currTarget.Kind != resource.KindGateway && currTarget.SectionName != nil { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -115,7 +115,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security if currTarget.Kind != resource.KindGateway && currTarget.SectionName == nil { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -133,7 +133,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security if currTarget.Kind == resource.KindGateway && currTarget.SectionName != nil { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } @@ -151,7 +151,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security if currTarget.Kind == resource.KindGateway && currTarget.SectionName == nil { policy, found := handledPolicies[policyName] if !found { - policy = currPolicy.DeepCopy() + policy = currPolicy handledPolicies[policyName] = policy res = append(res, policy) } diff --git a/internal/gatewayapi/testdata/extensions/extensionpolicy-tcp-listener.out.yaml b/internal/gatewayapi/testdata/extensions/extensionpolicy-tcp-listener.out.yaml index 41b161cbc3..9091747abd 100644 --- a/internal/gatewayapi/testdata/extensions/extensionpolicy-tcp-listener.out.yaml +++ b/internal/gatewayapi/testdata/extensions/extensionpolicy-tcp-listener.out.yaml @@ -162,6 +162,20 @@ xdsIR: 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 + controllerName: gateway.envoyproxy.io/gatewayclass-controller - object: apiVersion: foo.example.io/v1alpha1 kind: Bar @@ -175,6 +189,21 @@ xdsIR: kind: Gateway name: gateway-1 sectionName: tcp1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: tcp1 + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller globalResources: proxyServiceCluster: name: envoy-gateway/gateway-1 diff --git a/internal/gatewayapi/testdata/extensions/extensionpolicy-udp-listener.out.yaml b/internal/gatewayapi/testdata/extensions/extensionpolicy-udp-listener.out.yaml index 6282b46226..68600c04d2 100644 --- a/internal/gatewayapi/testdata/extensions/extensionpolicy-udp-listener.out.yaml +++ b/internal/gatewayapi/testdata/extensions/extensionpolicy-udp-listener.out.yaml @@ -162,6 +162,20 @@ xdsIR: 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 + controllerName: gateway.envoyproxy.io/gatewayclass-controller - object: apiVersion: foo.example.io/v1alpha1 kind: Bar @@ -175,6 +189,21 @@ xdsIR: kind: Gateway name: gateway-1 sectionName: udp1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: udp1 + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller globalResources: proxyServiceCluster: name: envoy-gateway/gateway-1 diff --git a/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target-array.out.yaml b/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target-array.out.yaml index 39fb71a8ba..a4806effd3 100644 --- a/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target-array.out.yaml +++ b/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target-array.out.yaml @@ -180,6 +180,32 @@ xdsIR: - group: gateway.networking.k8s.io kind: Gateway name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - 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 + controllerName: gateway.envoyproxy.io/gatewayclass-controller http: - address: 0.0.0.0 extensionRefs: @@ -263,6 +289,32 @@ xdsIR: - group: gateway.networking.k8s.io kind: Gateway name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller + - 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 + controllerName: gateway.envoyproxy.io/gatewayclass-controller globalResources: proxyServiceCluster: name: envoy-gateway/gateway-2 diff --git a/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target.out.yaml b/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target.out.yaml index 5df8dc3518..63495e3991 100644 --- a/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target.out.yaml +++ b/internal/gatewayapi/testdata/extensions/extensionpolicy-with-valid-target.out.yaml @@ -166,6 +166,20 @@ xdsIR: 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 + controllerName: gateway.envoyproxy.io/gatewayclass-controller - object: apiVersion: foo.example.io/v1alpha1 kind: Bar @@ -179,6 +193,21 @@ xdsIR: kind: Gateway name: gateway-1 sectionName: http2 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http2 + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller globalResources: proxyServiceCluster: name: envoy-gateway/gateway-1 diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index e19e24348d..f80fdc8c57 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -280,7 +280,7 @@ func (t *Translator) GetRelevantGateways(resources *resource.Resources) ( if gateway.Spec.GatewayClassName == t.GatewayClassName { gc := &GatewayContext{ - Gateway: gateway.DeepCopy(), + Gateway: gateway, } // Gateways that are not accepted by the controller because they reference an invalid EnvoyProxy. diff --git a/test/gobench/translate_test.go b/test/gobench/translate_test.go new file mode 100644 index 0000000000..cc1abaac14 --- /dev/null +++ b/test/gobench/translate_test.go @@ -0,0 +1,359 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package fuzz + +import ( + "fmt" + "strings" + "testing" + + "github.com/envoyproxy/gateway/internal/cmd/egctl" + "github.com/envoyproxy/gateway/internal/gatewayapi/resource" +) + +// Reused YAML snippets. +const ( + baseYAML = `apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: eg +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: eg + namespace: default +spec: + gatewayClassName: eg + listeners: + - name: http + protocol: HTTP + port: 80 + - name: https + protocol: HTTPS + port: 443 + tls: + mode: Terminate + certificateRefs: + - name: tls-secret + - name: grpc + protocol: HTTP + port: 81 + - name: udp + protocol: UDP + port: 82 +` + backendYAML = `--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: provided-backend + namespace: default +spec: + endpoints: + - ip: + address: 0.0.0.0 + port: 8000 +` + tlsSecretYAML = `--- +apiVersion: v1 +kind: Secret +metadata: + name: tls-secret + namespace: default +type: kubernetes.io/tls +data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURERENDQWZTZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrekNEWXdXaGNOTXpRdwpNakkyTUJUME1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOTE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ1pTT21NUlBXWkFqN08KcVFrTVc2d3Bub3NmVCtRMzhmVWJ1U3crRXlablZ1eUNuYlVGZjhIeTVyYkx1K2dObWszUW8xbnRBVTMzamprcwpXMGQzRHdCdWhKVUM0bkpVRks3cDk2dm9MQ2FTdmlPM0NQbytjUENPdkZ4K1ZrTzYxVkxXOEI2YW04UG5GWndhCmlGRGk0aUdyWXlIK3lsK2RUTmJoZlhIeEJ4T0E1M0IrcTI2K2ZmMFJXUWJKSWNiT1RzOENTSDZJWk1yeGNIcmsKOE1TdjFhWXlQdXpuT1BBQVFsNlRUdlEvNmhJZnF6bXJvd0RIRjRCMENFNUFvb2xFM0ZLT2kwaC9ieTJUN1dxbgo4NkdhdXA0VEtxVnV1Uk5hUU1CZDQ4azA4V3VTUENYSDBoWTVJbm1kdEMxRURKK3pQRk9NUjQycVA0THg5QWdICjNRZTBTMU5yQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +` + grpcRouteYAML = `--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: backend + namespace: default +spec: + parentRefs: + - name: eg + sectionName: grpc + hostnames: + - "www.grpc-example.com" + rules: + - matches: + - method: + service: com.example.Things + method: DoThing + headers: + - name: com.example.Header + value: foobar + backendRefs: + - name: provided-backend + port: 9000 +` + httpRouteYAML = `--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: backend + namespace: default +spec: + parentRefs: + - name: eg + hostnames: + - "www.example.com" + rules: + - backendRefs: + - name: provided-backend + port: 8000 +` + udpRouteYAML = `--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: UDPRoute +metadata: + name: backend + namespace: default +spec: + parentRefs: + - name: eg + sectionName: udp + rules: + - backendRefs: + - name: provided-backend + port: 3000 +` + securityPolicyYAML = `--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: security-policy + namespace: default +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: backend + cors: + allowOrigins: + - "https://www.example.com" + allowMethods: + - GET + - POST + allowHeaders: + - "Content-Type" +` + backendTrafficPolicyYAML = `--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: backend-traffic-policy + namespace: default +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: backend + circuitBreaker: + maxConnections: 100 + maxPendingRequests: 50 + loadBalancer: + type: RoundRobin +` + clientTrafficPolicyYAML = `--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: ClientTrafficPolicy +metadata: + name: client-traffic-policy + namespace: default +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: eg + timeout: + http: + requestReceivedTimeout: 30s +` +) + +// Helpers for benchmark policy generation. +func genSecurityPolicies(n int) string { + var sb strings.Builder + for i := 0; i < n; i++ { + sb.WriteString(fmt.Sprintf(`--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: security-policy-%d + namespace: default +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: backend-%d + cors: + allowOrigins: + - "https://www.example-%d.com" + allowMethods: + - GET + - POST + allowHeaders: + - "Content-Type" +`, i, i, i)) + } + return sb.String() +} + +func genBackendTrafficPolicies(n int) string { + var sb strings.Builder + for i := 0; i < n; i++ { + sb.WriteString(fmt.Sprintf(`--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: backend-traffic-policy-%d + namespace: default +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: backend-%d + circuitBreaker: + maxConnections: %d + maxPendingRequests: %d + loadBalancer: + type: RoundRobin +`, i, i, 100+i*10, 50+i*5)) + } + return sb.String() +} + +// Helpers for benchmark route generation. +func genHTTPRoutes(n int) string { + var sb strings.Builder + for i := 0; i < n; i++ { + sb.WriteString(fmt.Sprintf(`--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: backend-%d + namespace: default +spec: + parentRefs: + - name: eg + hostnames: + - "www.example-%d.com" + rules: + - backendRefs: + - name: provided-backend + port: 8000 +`, i, i)) + } + return sb.String() +} + +func genGRPCRoutes(n int) string { + var sb strings.Builder + for i := 0; i < n; i++ { + sb.WriteString(fmt.Sprintf(`--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: backend-grpc-%d + namespace: default +spec: + parentRefs: + - name: eg + sectionName: grpc + hostnames: + - "www.grpc-%d.example.com" + rules: + - matches: + - method: + service: com.example.Service%d + method: Call + backendRefs: + - name: provided-backend + port: 9000 +`, i, i, i)) + } + return sb.String() +} + +func genUDPRoutes(n int) string { + var sb strings.Builder + for i := 0; i < n; i++ { + sb.WriteString(fmt.Sprintf(`--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: UDPRoute +metadata: + name: backend-udp-%d + namespace: default +spec: + parentRefs: + - name: eg + sectionName: udp + rules: + - backendRefs: + - name: provided-backend + port: %d +`, i, 3000+i)) + } + return sb.String() +} + +// Benchmark cases: small / medium / large. +func BenchmarkGatewayAPItoXDS(b *testing.B) { + type benchCase struct { + name string + yaml string + } + medium := baseYAML + backendYAML + tlsSecretYAML + clientTrafficPolicyYAML + + genHTTPRoutes(100) + + genGRPCRoutes(50) + + genUDPRoutes(20) + + genSecurityPolicies(100) + + genBackendTrafficPolicies(100) + large := baseYAML + backendYAML + tlsSecretYAML + clientTrafficPolicyYAML + + genHTTPRoutes(1000) + + genGRPCRoutes(500) + + genUDPRoutes(100) + + genSecurityPolicies(1000) + + genBackendTrafficPolicies(1000) + + cases := []benchCase{ + { + name: "small", + yaml: baseYAML + httpRouteYAML + backendYAML + tlsSecretYAML + securityPolicyYAML + backendTrafficPolicyYAML + clientTrafficPolicyYAML, + }, + { + name: "medium", + yaml: medium, + }, + { + name: "large", + yaml: large, + }, + } + + for _, tc := range cases { + b.Run(tc.name, func(b *testing.B) { + rs, err := resource.LoadResourcesFromYAMLBytes([]byte(tc.yaml), true) + if err != nil { + b.Fatalf("load: %v", err) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err = egctl.TranslateGatewayAPIToXds("default", "cluster.local", "all", rs) + if err != nil && strings.Contains(err.Error(), "failed to translate xds") { + b.Fatalf("%v", err) + } + } + }) + } +} From b8951438f217449921b08d770ce8f6a176673c09 Mon Sep 17 00:00:00 2001 From: Rudrakh Panigrahi Date: Fri, 12 Sep 2025 23:06:55 +0530 Subject: [PATCH 18/27] fix: validation for grpc routes with extension ref filters (#6949) Signed-off-by: Rudrakh Panigrahi Signed-off-by: zirain --- internal/gatewayapi/filters.go | 2 +- ...croute-with-valid-extension-filter.in.yaml | 48 +++++ ...route-with-valid-extension-filter.out.yaml | 184 ++++++++++++++++++ release-notes/current.yaml | 1 + 4 files changed, 234 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 be65cb0bef..b4fa79d79f 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 diff --git a/release-notes/current.yaml b/release-notes/current.yaml index f659471105..3852b1ef24 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -19,6 +19,7 @@ bug fixes: | Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. Fixed Lua validator log level to be suppressed by default. Fixed ProxyTopologyInjector cache sync race condition that caused injection failures + Fixed validation for grpc routes with extension ref filters. # Enhancements that improve performance. performance improvements: | From 8d8c7c61dcc58d2d629390f4a182dc43c63fab5e Mon Sep 17 00:00:00 2001 From: Youssef Rabie Date: Sat, 13 Sep 2025 04:03:23 +0300 Subject: [PATCH 19/27] fix: cleanup dangling route status conditions (#6812) Signed-off-by: y-rabie Signed-off-by: zirain --- 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 e9abf085a1..29ec951146 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 97d0ac81c90fe4091a1ce967f8bbdff268e4a7cb Mon Sep 17 00:00:00 2001 From: Sudipto Baral Date: Sat, 13 Sep 2025 01:53:53 -0400 Subject: [PATCH 20/27] 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: zirain --- 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 c107e3cf57..c975b122cc 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 cacf995d86c6d5d792ff9e05bd5d07ff3fbc0f19 Mon Sep 17 00:00:00 2001 From: shahar-h Date: Sun, 14 Sep 2025 18:27:24 +0300 Subject: [PATCH 21/27] fix: update distroless image to resolve glibc CVEs (#6953) Signed-off-by: Shahar Harari Signed-off-by: zirain --- 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 f9b2aa70b1..0911b964a1 100644 --- a/tools/docker/envoy-gateway/Dockerfile +++ b/tools/docker/envoy-gateway/Dockerfile @@ -4,7 +4,7 @@ RUN mkdir -p /var/lib/eg && chmod -R 0777 /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:fa7b50f111719aaf5f7435383b6d05f12277f3ce9514bc0a62759374a04d6bae +FROM gcr.io/distroless/base-nossl:nonroot@sha256:a1922debbf4ff2cc245d7c0d1e2021cfcee35fe24afae7505aeec59f7e7802f6 ARG TARGETPLATFORM COPY $TARGETPLATFORM/envoy-gateway /usr/local/bin/ COPY --from=source /var/lib /var/lib From 3b3d11a569a886c1571c6958d5e7f0b83dd24ddc Mon Sep 17 00:00:00 2001 From: zirain Date: Mon, 15 Sep 2025 12:52:10 +0800 Subject: [PATCH 22/27] chore: bump golang to 1.24.7 (#6959) chore: bump golang Signed-off-by: zirain --- examples/envoy-ext-auth/Dockerfile | 2 +- examples/envoy-ext-auth/go.mod | 2 +- examples/extension-server/go.mod | 2 +- examples/grpc-ext-proc/Dockerfile | 2 +- examples/grpc-ext-proc/go.mod | 2 +- examples/preserve-case-backend/Dockerfile | 2 +- examples/preserve-case-backend/go.mod | 2 +- examples/simple-extension-server/Dockerfile | 2 +- examples/simple-extension-server/go.mod | 2 +- examples/static-file-server/Dockerfile | 2 +- examples/static-file-server/go.mod | 2 +- go.mod | 2 +- site/go.mod | 2 +- tools/go.mod | 352 ++++++++++++++ tools/go.sum | 495 ++++++++++++++++++++ 15 files changed, 860 insertions(+), 13 deletions(-) create mode 100644 tools/go.mod create mode 100644 tools/go.sum diff --git a/examples/envoy-ext-auth/Dockerfile b/examples/envoy-ext-auth/Dockerfile index fa3ccbfe4d..64a85c41bf 100644 --- a/examples/envoy-ext-auth/Dockerfile +++ b/examples/envoy-ext-auth/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6 AS builder +FROM golang:1.24.7 AS builder ARG GO_LDFLAGS="" diff --git a/examples/envoy-ext-auth/go.mod b/examples/envoy-ext-auth/go.mod index 8e6237f15c..c6a099b470 100644 --- a/examples/envoy-ext-auth/go.mod +++ b/examples/envoy-ext-auth/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-grcp-ext-auth -go 1.24.6 +go 1.24.7 require ( github.com/envoyproxy/go-control-plane/envoy v1.32.4 diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod index 9a01121bb6..d3207a42e7 100644 --- a/examples/extension-server/go.mod +++ b/examples/extension-server/go.mod @@ -1,6 +1,6 @@ module github.com/exampleorg/envoygateway-extension -go 1.24.6 +go 1.24.7 require ( github.com/envoyproxy/gateway v1.3.1 diff --git a/examples/grpc-ext-proc/Dockerfile b/examples/grpc-ext-proc/Dockerfile index 05a387bcf6..8cf7eb1137 100644 --- a/examples/grpc-ext-proc/Dockerfile +++ b/examples/grpc-ext-proc/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6 AS builder +FROM golang:1.24.7 AS builder ARG GO_LDFLAGS="" diff --git a/examples/grpc-ext-proc/go.mod b/examples/grpc-ext-proc/go.mod index 6f03773f19..584b047430 100644 --- a/examples/grpc-ext-proc/go.mod +++ b/examples/grpc-ext-proc/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-grpc-ext-proc -go 1.24.6 +go 1.24.7 require ( github.com/envoyproxy/go-control-plane/envoy v1.32.4 diff --git a/examples/preserve-case-backend/Dockerfile b/examples/preserve-case-backend/Dockerfile index 99f8486502..4976a63806 100644 --- a/examples/preserve-case-backend/Dockerfile +++ b/examples/preserve-case-backend/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6 AS builder +FROM golang:1.24.7 AS builder ARG GO_LDFLAGS="" diff --git a/examples/preserve-case-backend/go.mod b/examples/preserve-case-backend/go.mod index f6deb55adf..55573da549 100644 --- a/examples/preserve-case-backend/go.mod +++ b/examples/preserve-case-backend/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-preserve-case-backend -go 1.24.6 +go 1.24.7 require github.com/valyala/fasthttp v1.64.0 diff --git a/examples/simple-extension-server/Dockerfile b/examples/simple-extension-server/Dockerfile index 9a0f01e76c..42172f685d 100644 --- a/examples/simple-extension-server/Dockerfile +++ b/examples/simple-extension-server/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6 AS builder +FROM golang:1.24.7 AS builder ARG GO_LDFLAGS="" diff --git a/examples/simple-extension-server/go.mod b/examples/simple-extension-server/go.mod index 3d5ca39a5c..5f771d0f3b 100644 --- a/examples/simple-extension-server/go.mod +++ b/examples/simple-extension-server/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway-simple-extension-server -go 1.24.6 +go 1.24.7 require ( github.com/envoyproxy/gateway v1.4.2 diff --git a/examples/static-file-server/Dockerfile b/examples/static-file-server/Dockerfile index a0c1bddb1d..e53ff75545 100644 --- a/examples/static-file-server/Dockerfile +++ b/examples/static-file-server/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24.6 AS builder +FROM golang:1.24.7 AS builder ARG GO_LDFLAGS="" diff --git a/examples/static-file-server/go.mod b/examples/static-file-server/go.mod index d544e4d171..092e99e5e9 100644 --- a/examples/static-file-server/go.mod +++ b/examples/static-file-server/go.mod @@ -1,3 +1,3 @@ module github.com/envoyproxy/static-file-server -go 1.24.6 +go 1.24.7 diff --git a/go.mod b/go.mod index 24f7ff50f8..396c54fcb0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/envoyproxy/gateway -go 1.24.6 +go 1.24.7 // Replace the otelgrpc version because of k8s.io/client-go v0.33.3 replace go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 diff --git a/site/go.mod b/site/go.mod index 841bb671f2..f4700f1891 100644 --- a/site/go.mod +++ b/site/go.mod @@ -1,6 +1,6 @@ module github.com/google/docsy-example -go 1.24.6 +go 1.24.7 require ( github.com/FortAwesome/Font-Awesome v0.0.0-20241216213156-af620534bfc3 // indirect diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 0000000000..af9397d90f --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,352 @@ +module tools + +go 1.24.7 + +tool ( + github.com/bufbuild/buf/cmd/buf + github.com/elastic/crd-ref-docs + github.com/golangci/golangci-lint/v2/cmd/golangci-lint + github.com/google/go-jsonnet/cmd/jsonnet + github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb + github.com/norwoodj/helm-docs/cmd/helm-docs + google.golang.org/grpc/cmd/protoc-gen-go-grpc + google.golang.org/protobuf/cmd/protoc-gen-go + sigs.k8s.io/controller-runtime/tools/setup-envtest + sigs.k8s.io/controller-tools/cmd/controller-gen + sigs.k8s.io/kind/cmd/kind +) + +require ( + 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect + 4d63.com/gochecknoglobals v0.2.2 // indirect + al.essio.dev/pkg/shellescape v1.5.1 // indirect + buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.6-20250718181942-e35f9b667443.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250717185734-6c6e0d3c608e.1 // indirect + buf.build/gen/go/bufbuild/registry/connectrpc/go v1.18.1-20250721151928-2b7ae473b098.1 // indirect + buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.6-20250721151928-2b7ae473b098.1 // indirect + buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.6-20241007202033-cf42259fcbfc.1 // indirect + buf.build/go/app v0.1.0 // indirect + buf.build/go/bufplugin v0.9.0 // indirect + buf.build/go/interrupt v1.1.0 // indirect + buf.build/go/protovalidate v0.14.0 // indirect + buf.build/go/protoyaml v0.6.0 // indirect + buf.build/go/spdx v0.2.0 // indirect + buf.build/go/standard v0.1.0 // indirect + cel.dev/expr v0.24.0 // indirect + codeberg.org/chavacava/garif v0.2.0 // indirect + connectrpc.com/connect v1.18.1 // indirect + connectrpc.com/otelconnect v0.7.2 // indirect + dario.cat/mergo v1.0.1 // indirect + dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect + dev.gaijin.team/go/golib v0.6.0 // indirect + github.com/4meepo/tagalign v1.4.3 // indirect + github.com/Abirdcfly/dupword v0.1.6 // indirect + github.com/AlwxSin/noinlineerr v1.0.5 // indirect + github.com/Antonboom/errname v1.1.0 // indirect + github.com/Antonboom/nilnil v1.1.0 // indirect + github.com/Antonboom/testifylint v1.6.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/semver/v3 v3.3.1 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect + github.com/alecthomas/chroma/v2 v2.20.0 // indirect + github.com/alecthomas/go-check-sumtype v0.3.1 // indirect + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/alexkohler/nakedret/v2 v2.0.6 // indirect + github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/alfatraining/structtag v1.0.0 // indirect + github.com/alingse/asasalint v0.0.11 // indirect + github.com/alingse/nilnesserr v0.2.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/ashanbrown/forbidigo/v2 v2.1.0 // indirect + github.com/ashanbrown/makezero/v2 v2.0.1 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bkielbasa/cyclop v1.2.3 // indirect + github.com/blizzy78/varnamelen v0.8.0 // indirect + github.com/bombsimon/wsl/v4 v4.7.0 // indirect + github.com/bombsimon/wsl/v5 v5.1.1 // indirect + github.com/breml/bidichk v0.3.3 // indirect + github.com/breml/errchkjson v0.4.1 // indirect + github.com/bufbuild/buf v1.56.0 // indirect + github.com/bufbuild/protocompile v0.14.1 // indirect + github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect + github.com/butuzov/ireturn v0.4.0 // indirect + github.com/butuzov/mirror v1.3.0 // indirect + github.com/catenacyber/perfsprint v0.9.1 // indirect + github.com/ccojocar/zxcvbn-go v1.0.4 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charithe/durationcheck v0.0.10 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/lipgloss v1.1.0 // indirect + github.com/charmbracelet/x/ansi v0.8.0 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/ckaznocha/intrange v0.3.1 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/curioswitch/go-reassign v0.3.0 // indirect + github.com/daixiang0/gci v0.13.7 // indirect + github.com/dave/dst v0.27.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/denis-tingaikin/go-header v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/docker/cli v28.3.3+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v28.3.3+incompatible // indirect + github.com/docker/docker-credential-helpers v0.9.3 // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/elastic/crd-ref-docs v0.2.0 // indirect + github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect + github.com/ettle/strcase v0.2.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/fatih/structtag v1.2.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/firefart/nonamedreturns v1.0.6 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/fzipp/gocyclo v0.6.0 // indirect + github.com/ghostiam/protogetter v0.3.15 // indirect + github.com/go-chi/chi/v5 v5.2.2 // indirect + github.com/go-critic/go-critic v0.13.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-toolsmith/astcast v1.1.0 // indirect + github.com/go-toolsmith/astcopy v1.1.0 // indirect + github.com/go-toolsmith/astequal v1.2.0 // indirect + github.com/go-toolsmith/astfmt v1.1.0 // indirect + github.com/go-toolsmith/astp v1.1.0 // indirect + github.com/go-toolsmith/strparse v1.1.0 // indirect + github.com/go-toolsmith/typep v1.1.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect + github.com/gobuffalo/flect v1.0.3 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect + github.com/gofrs/flock v0.12.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect + github.com/golangci/go-printf-func-name v0.1.0 // indirect + github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect + github.com/golangci/golangci-lint/v2 v2.4.0 // indirect + github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 // indirect + github.com/golangci/misspell v0.7.0 // indirect + github.com/golangci/plugin-module-register v0.1.2 // indirect + github.com/golangci/revgrep v0.8.0 // indirect + github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect + github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-containerregistry v0.20.6 // indirect + github.com/google/go-jsonnet v0.21.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gordonklaus/ineffassign v0.1.0 // indirect + github.com/gostaticanalysis/analysisutil v0.7.1 // indirect + github.com/gostaticanalysis/comment v1.5.0 // indirect + github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jdx/go-netrc v1.0.0 // indirect + github.com/jgautheron/goconst v1.8.2 // indirect + github.com/jingyugao/rowserrcheck v1.1.1 // indirect + github.com/jjti/go-spancheck v0.6.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/jsonnet-bundler/jsonnet-bundler v0.6.0 // indirect + github.com/julz/importas v0.2.0 // indirect + github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect + github.com/kisielk/errcheck v1.9.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.6 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/kulti/thelper v0.6.3 // indirect + github.com/kunwardeep/paralleltest v1.0.14 // indirect + github.com/lasiar/canonicalheader v1.1.2 // indirect + github.com/ldez/exptostd v0.4.4 // indirect + github.com/ldez/gomoddirectives v0.7.0 // indirect + github.com/ldez/grignotin v0.10.0 // indirect + github.com/ldez/tagliatelle v0.7.1 // indirect + github.com/ldez/usetesting v0.5.0 // indirect + github.com/leonklingele/grouper v1.1.2 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/macabu/inamedparam v0.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/manuelarte/embeddedstructfieldcheck v0.3.0 // indirect + github.com/manuelarte/funcorder v0.5.0 // indirect + github.com/maratori/testableexamples v1.0.0 // indirect + github.com/maratori/testpackage v1.1.1 // indirect + github.com/matoous/godox v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mgechev/revive v1.11.0 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/moricho/tparallel v0.3.2 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nakabonne/nestif v0.3.1 // indirect + github.com/nishanths/exhaustive v0.12.0 // indirect + github.com/nishanths/predeclared v0.2.2 // indirect + github.com/norwoodj/helm-docs v1.14.2 // indirect + github.com/nunnatsa/ginkgolinter v0.20.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/polyfloyd/go-errorlint v1.8.0 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/quasilyte/go-ruleguard v0.4.4 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect + github.com/quasilyte/gogrep v0.5.0 // indirect + github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect + github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/raeperd/recvcheck v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/ryancurrah/gomodguard v1.4.1 // indirect + github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect + github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/sashamelentyev/interfacebloat v1.1.0 // indirect + github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect + github.com/securego/gosec/v2 v2.22.7 // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/encoding v0.5.3 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sivchari/containedctx v1.0.3 // indirect + github.com/sonatard/noctx v0.4.0 // indirect + github.com/sourcegraph/go-diff v0.7.0 // indirect + github.com/spf13/afero v1.14.0 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/cobra v1.9.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.7 // indirect + github.com/spf13/viper v1.16.0 // indirect + github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect + github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect + github.com/stoewer/go-strcase v1.3.1 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.10.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/tdakkota/asciicheck v0.4.1 // indirect + github.com/tetafro/godot v1.5.1 // indirect + github.com/tetratelabs/wazero v1.9.0 // indirect + github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect + github.com/timonwong/loggercheck v0.11.0 // indirect + github.com/tomarrell/wrapcheck/v2 v2.11.0 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect + github.com/ultraware/funlen v0.2.0 // indirect + github.com/ultraware/whitespace v0.2.0 // indirect + github.com/uudashr/gocognit v1.2.0 // indirect + github.com/uudashr/iface v1.4.1 // indirect + github.com/vbatts/tar-split v0.12.1 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xen0n/gosmopolitan v1.3.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/yagipy/maintidx v1.0.0 // indirect + github.com/yeya24/promlinter v0.3.0 // indirect + github.com/ykadowak/zerologlint v0.1.5 // indirect + gitlab.com/bosi/decorder v0.4.2 // indirect + go-simpler.org/musttag v0.13.1 // indirect + go-simpler.org/sloglint v0.11.1 // indirect + go.augendre.info/arangolint v0.2.0 // indirect + go.augendre.info/fatcontext v0.8.0 // indirect + go.lsp.dev/jsonrpc2 v0.10.0 // indirect + go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect + go.lsp.dev/protocol v0.12.0 // indirect + go.lsp.dev/uri v0.3.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect + go.uber.org/mock v0.5.2 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect + golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/mod v0.27.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/tools v0.36.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect + google.golang.org/protobuf v1.36.7 // indirect + gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + helm.sh/helm/v3 v3.18.6 // indirect + honnef.co/go/tools v0.6.1 // indirect + k8s.io/api v0.33.3 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect + k8s.io/apimachinery v0.34.0-rc.1 // indirect + k8s.io/code-generator v0.33.3 // indirect + k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect + mvdan.cc/gofumpt v0.8.0 // indirect + mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect + pluginrpc.com/pluginrpc v0.5.0 // indirect + sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250819114936-e4f9a2446c3d // indirect + sigs.k8s.io/controller-tools v0.18.0 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/kind v0.29.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/tools/go.sum b/tools/go.sum new file mode 100644 index 0000000000..8f8aafa994 --- /dev/null +++ b/tools/go.sum @@ -0,0 +1,495 @@ +4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= +4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= +al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= +buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.6-20250718181942-e35f9b667443.1/go.mod h1:TsmeaGU5CZAF7zRM05vIKgXh56GgwaoMS8X+a77RV5Q= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250717185734-6c6e0d3c608e.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= +buf.build/gen/go/bufbuild/registry/connectrpc/go v1.18.1-20250721151928-2b7ae473b098.1/go.mod h1:/MMEAJmz7PEmksjkSxhWXell82FXiG7BLUPBJRmKBsA= +buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.6-20250721151928-2b7ae473b098.1/go.mod h1:RsJBKYlgzsbl5LAhIu0cNrPPzBNenMLTAAykRxFidtw= +buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.6-20241007202033-cf42259fcbfc.1/go.mod h1:OUbhXurY+VHFGn9FBxcRy8UB7HXk9NvJ2qCgifOMypQ= +buf.build/go/app v0.1.0/go.mod h1:0XVOYemubVbxNXVY0DnsVgWeGkcbbAvjDa1fmhBC+Wo= +buf.build/go/bufplugin v0.9.0/go.mod h1:Z0CxA3sKQ6EPz/Os4kJJneeRO6CjPeidtP1ABh5jPPY= +buf.build/go/interrupt v1.1.0/go.mod h1:ql56nXPG1oHlvZa6efNC7SKAQ/tUjS6z0mhJl0gyeRM= +buf.build/go/protovalidate v0.14.0/go.mod h1:+F/oISho9MO7gJQNYC2VWLzcO1fTPmaTA08SDYJZncA= +buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q= +buf.build/go/spdx v0.2.0/go.mod h1:bXdwQFem9Si3nsbNy8aJKGPoaPi5DKwdeEp5/ArZ6w8= +buf.build/go/standard v0.1.0/go.mod h1:PiqpHz/7ZFq+kqvYhc/SK3lxFIB9N/aiH2CFC2JHIQg= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= +connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/otelconnect v0.7.2/go.mod h1:JS7XUKfuJs2adhCnXhNHPHLz6oAaZniCJdSF00OZSew= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= +dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= +github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= +github.com/Abirdcfly/dupword v0.1.6/go.mod h1:s+BFMuL/I4YSiFv29snqyjwzDp4b65W2Kvy+PKzZ6cw= +github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= +github.com/Antonboom/errname v1.1.0/go.mod h1:O1NMrzgUcVBGIfi3xlVuvX8Q/VP/73sseCaAppfjqZw= +github.com/Antonboom/nilnil v1.1.0/go.mod h1:b7sAlogQjFa1wV8jUW3o4PMzDVFLbTux+xnQdvzdcIE= +github.com/Antonboom/testifylint v1.6.1/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FAnbZV+ZRrnXPLI= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= +github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA= +github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/ashanbrown/forbidigo/v2 v2.1.0/go.mod h1:0zZfdNAuZIL7rSComLGthgc/9/n2FqspBOH90xlCHdA= +github.com/ashanbrown/makezero/v2 v2.0.1/go.mod h1:kKU4IMxmYW1M4fiEHMb2vc5SFoPzXvgbMR9gIp5pjSw= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= +github.com/bombsimon/wsl/v5 v5.1.1/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= +github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= +github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= +github.com/bufbuild/buf v1.56.0/go.mod h1:uDNMYshCJIXL99OQc71SDeFiDqOse9sSHXPpZlrqElw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ= +github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= +github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= +github.com/catenacyber/perfsprint v0.9.1/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM= +github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/stargz-snapshotter/estargz v0.17.0/go.mod h1:s06tWAiJcXQo9/8AReBCIo/QxcXFZ2n4qfsRnpl71SM= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= +github.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ= +github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/elastic/crd-ref-docs v0.2.0/go.mod h1:0bklkJhTG7nC6AVsdDi0wt5bGoqvzdZSzMMQkilZ6XM= +github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= +github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/ghostiam/protogetter v0.3.15/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= +github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= +github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= +github.com/golangci/golangci-lint/v2 v2.4.0/go.mod h1:Oq7vuAf6L1iNL34uHDcsIF6Mnc0amOPdsT3/GlpHD+I= +github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ= +github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= +github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= +github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= +github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y= +github.com/google/go-jsonnet v0.21.0/go.mod h1:tCGAu8cpUpEZcdGMmdOu37nh8bGgqubhI5v2iSk3KJQ= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= +github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jdx/go-netrc v1.0.0/go.mod h1:Gh9eFQJnoTNIRHXl2j5bJXA1u84hQWJWgGh569zF3v8= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jsonnet-bundler/jsonnet-bundler v0.6.0/go.mod h1:5esRxD59TyScj6qxT3o7GH0sryBKvVmx2zaEYDXtQkg= +github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= +github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.14/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= +github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= +github.com/ldez/exptostd v0.4.4/go.mod h1:QfdzPw6oHjFVdNV7ILoPu5sw3OZ3OG1JS0I5JN3J4Js= +github.com/ldez/gomoddirectives v0.7.0/go.mod h1:wR4v8MN9J8kcwvrkzrx6sC9xe9Cp68gWYCsda5xvyGc= +github.com/ldez/grignotin v0.10.0/go.mod h1:oR4iCKUP9fwoeO6vCQeD7M5SMxCT6xdVas4vg0h1LaI= +github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I= +github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= +github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/manuelarte/embeddedstructfieldcheck v0.3.0/go.mod h1:LSo/IQpPfx1dXMcX4ibZCYA7Yy6ayZHIaOGM70+1Wy8= +github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mgechev/revive v1.11.0/go.mod h1:tI0oLF/2uj+InHCBLrrqfTKfjtFTBCFFfG05auyzgdw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/norwoodj/helm-docs v1.14.2/go.mod h1:qdo76rorOkPDme8nsV5e0JBAYrs56kzvZMYW83k1kgc= +github.com/nunnatsa/ginkgolinter v0.20.0/go.mod h1:dCIuFlTPfQerXgGUju3VygfAFPdC5aE1mdacCDKDJcQ= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/quasilyte/go-ruleguard v0.4.4/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= +github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= +github.com/securego/gosec/v2 v2.22.7/go.mod h1:510TFNDMrIPytokyHQAVLvPeDr41Yihn2ak8P+XQfNE= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sonatard/noctx v0.4.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= +github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tdakkota/asciicheck v0.4.1/go.mod h1:0k7M3rCfRXb0Z6bwgvkEIMleKH3kXNz9UqJ9Xuqopr8= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.5.1/go.mod h1:cCdPtEndkmqqrhiCfkmxDodMQJ/f3L1BCNskCUZdTwk= +github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/tomarrell/wrapcheck/v2 v2.11.0/go.mod h1:wFL9pDWDAbXhhPZZt+nG8Fu+h29TtnZ2MW6Lx4BRXIU= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= +github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= +github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= +github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= +github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= +go-simpler.org/musttag v0.13.1/go.mod h1:8r450ehpMLQgvpb6sg+hV5Ur47eH6olp/3yEanfG97k= +go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= +go.augendre.info/arangolint v0.2.0/go.mod h1:Vx4KSJwu48tkE+8uxuf0cbBnAPgnt8O1KWiT7bljq7w= +go.augendre.info/fatcontext v0.8.0/go.mod h1:oVJfMgwngMsHO+KB2MdgzcO+RvtNdiCEOlWvSFtax/s= +go.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac= +go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2/go.mod h1:gtSHRuYfbCT0qnbLnovpie/WEmqyJ7T4n6VXiFMBtcw= +go.lsp.dev/protocol v0.12.0/go.mod h1:Qb11/HgZQ72qQbeyPfJbu3hZBH23s1sr4st8czGeDMQ= +go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20250620022241-b7579e27df2b/go.mod h1:LKZHyeOpPuZcMgxeHjJp4p5yvxrCX1xDvH10zYHhjjQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.18.6/go.mod h1:L/dXDR2r539oPlFP1PJqKAC1CUgqHJDLkxKpDGrWnyg= +honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= +k8s.io/apimachinery v0.34.0-rc.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/code-generator v0.33.3/go.mod h1:6Y02+HQJYgNphv9z3wJB5w+sjYDIEBQW7sh62PkufvA= +k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg= +mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE= +pluginrpc.com/pluginrpc v0.5.0/go.mod h1:UNWZ941hcVAoOZUn8YZsMmOZBzbUjQa3XMns8RQLp9o= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250819114936-e4f9a2446c3d/go.mod h1:f9/k6JI1T3ROlGzlrAEnIFMXypFWgx5p1zYgFAEIfYE= +sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kind v0.29.0/go.mod h1:ldWQisw2NYyM6k64o/tkZng/1qQW7OlzcN5a8geJX3o= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= From 9581cff1d3b6b02e837a60f434fb4c165e1b48c9 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Mon, 15 Sep 2025 18:25:31 -0700 Subject: [PATCH 23/27] fix: Make sure proxy protocol filter is the first listener filter (#6972) Fixes: https://github.com/envoyproxy/gateway/issues/6873 Signed-off-by: Arko Dasgupta Co-authored-by: Jacob Neil Taylor Signed-off-by: zirain --- internal/xds/translator/proxy_protocol.go | 4 +- .../xds-ir/listener-proxy-protocol-multi.yaml | 44 +++++++++++++ ...istener-proxy-protocol-multi.clusters.yaml | 48 ++++++++++++++ ...stener-proxy-protocol-multi.endpoints.yaml | 24 +++++++ ...stener-proxy-protocol-multi.listeners.yaml | 65 +++++++++++++++++++ .../listener-proxy-protocol-multi.routes.yaml | 25 +++++++ ...listener-proxy-protocol-multi.secrets.yaml | 12 ++++ 7 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 internal/xds/translator/testdata/in/xds-ir/listener-proxy-protocol-multi.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.routes.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.secrets.yaml diff --git a/internal/xds/translator/proxy_protocol.go b/internal/xds/translator/proxy_protocol.go index 453cb0ed29..ada9bd3017 100644 --- a/internal/xds/translator/proxy_protocol.go +++ b/internal/xds/translator/proxy_protocol.go @@ -6,6 +6,8 @@ package translator import ( + "slices" + listenerv3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" proxyprotocolv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/listener/proxy_protocol/v3" "github.com/envoyproxy/go-control-plane/pkg/wellknown" @@ -37,7 +39,7 @@ func patchProxyProtocolFilter(xdsListener *listenerv3.Listener, proxyProtocolSet // Build and patch the Proxy Protocol Filter. filter := buildProxyProtocolFilter(proxyProtocolSettings) if filter != nil { - xdsListener.ListenerFilters = append(xdsListener.ListenerFilters, filter) + xdsListener.ListenerFilters = slices.Insert(xdsListener.ListenerFilters, 0, filter) } } diff --git a/internal/xds/translator/testdata/in/xds-ir/listener-proxy-protocol-multi.yaml b/internal/xds/translator/testdata/in/xds-ir/listener-proxy-protocol-multi.yaml new file mode 100644 index 0000000000..bd6e7acb73 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/listener-proxy-protocol-multi.yaml @@ -0,0 +1,44 @@ +http: +- name: "listener" + address: "::" + port: 10080 + hostnames: + - "foo.com" + - "bar.com" + path: + mergeSlashes: true + escapedSlashesAction: UnescapeAndRedirect + tls: + alpnProtocols: + - h2 + - http/1.1 + certificates: + - name: secret-1 + # byte slice representation of "key-data" + certificate: [99, 101, 114, 116, 45, 100, 97, 116, 97] + # byte slice representation of "key-data" + privateKey: [107, 101, 121, 45, 100, 97, 116, 97] + - name: secret-2 + certificate: [99, 101, 114, 116, 45, 100, 97, 116, 97] + privateKey: [107, 101, 121, 45, 100, 97, 116, 97] + proxyProtocol: + optional: false + routes: + - name: "first-route" + hostname: "foo.com" + destination: + name: "first-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + name: "first-route-dest/backend/0" + - name: "second-route" + hostname: "bar.com" + destination: + name: "second-route-dest" + settings: + - endpoints: + - host: "5.6.7.8" + port: 50000 + name: "second-route-dest/backend/0" diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.clusters.yaml new file mode 100644 index 0000000000..7e9eb80719 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.clusters.yaml @@ -0,0 +1,48 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: first-route-dest + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: first-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: second-route-dest + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: second-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.endpoints.yaml new file mode 100644 index 0000000000..39102da400 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.endpoints.yaml @@ -0,0 +1,24 @@ +- clusterName: first-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.2.3.4 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: first-route-dest/backend/0 +- clusterName: second-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 5.6.7.8 + portValue: 50000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: second-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.listeners.yaml new file mode 100644 index 0000000000..4a01e1c2f6 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.listeners.yaml @@ -0,0 +1,65 @@ +- address: + socketAddress: + address: '::' + portValue: 10080 + filterChains: + - filterChainMatch: + serverNames: + - foo.com + - bar.com + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: https-10080 + useRemoteAddress: true + name: listener + transportSocket: + name: envoy.transport_sockets.tls + typedConfig: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + commonTlsContext: + alpnProtocols: + - h2 + - http/1.1 + tlsCertificateSdsSecretConfigs: + - name: secret-1 + sdsConfig: + ads: {} + resourceApiVersion: V3 + - name: secret-2 + sdsConfig: + ads: {} + resourceApiVersion: V3 + disableStatefulSessionResumption: true + disableStatelessSessionResumption: true + listenerFilters: + - name: envoy.filters.listener.proxy_protocol + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol + - name: envoy.filters.listener.tls_inspector + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector + maxConnectionsToAcceptPerSocketEvent: 1 + name: listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.routes.yaml new file mode 100644 index 0000000000..21193de51f --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.routes.yaml @@ -0,0 +1,25 @@ +- ignorePortInHostMatching: true + name: listener + virtualHosts: + - domains: + - foo.com + name: listener/foo_com + routes: + - match: + prefix: / + name: first-route + route: + cluster: first-route-dest + upgradeConfigs: + - upgradeType: websocket + - domains: + - bar.com + name: listener/bar_com + routes: + - match: + prefix: / + name: second-route + route: + cluster: second-route-dest + upgradeConfigs: + - upgradeType: websocket diff --git a/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.secrets.yaml b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.secrets.yaml new file mode 100644 index 0000000000..ad88ffe43c --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/listener-proxy-protocol-multi.secrets.yaml @@ -0,0 +1,12 @@ +- name: secret-1 + tlsCertificate: + certificateChain: + inlineBytes: Y2VydC1kYXRh + privateKey: + inlineBytes: a2V5LWRhdGE= +- name: secret-2 + tlsCertificate: + certificateChain: + inlineBytes: Y2VydC1kYXRh + privateKey: + inlineBytes: a2V5LWRhdGE= From 8742fe016cd9e6bd40cbc2d06894caa29346da4f Mon Sep 17 00:00:00 2001 From: zirain Date: Tue, 16 Sep 2025 10:45:13 +0800 Subject: [PATCH 24/27] release notes Signed-off-by: zirain --- release-notes/current.yaml | 10 ---------- release-notes/v1.5.1.yaml | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 release-notes/v1.5.1.yaml diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 3852b1ef24..3271a4f907 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -10,16 +10,6 @@ security updates: | new features: | bug fixes: | - Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. - Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy. - Fixed the topologyInjectorDisabled and the local cluster was not defined. - Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. - Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. - Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. - Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. - Fixed Lua validator log level to be suppressed by default. - Fixed ProxyTopologyInjector cache sync race condition that caused injection failures - Fixed validation for grpc routes with extension ref filters. # Enhancements that improve performance. performance improvements: | diff --git a/release-notes/v1.5.1.yaml b/release-notes/v1.5.1.yaml new file mode 100644 index 0000000000..0cbbda2ccc --- /dev/null +++ b/release-notes/v1.5.1.yaml @@ -0,0 +1,31 @@ +date: September 16, 2024 + +# Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs. +breaking changes: | + +# Updates addressing vulnerabilities, security flaws, or compliance requirements. +security updates: | + +# New features or capabilities added in this release. +new features: | + +bug fixes: | + Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. + Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy. + Fixed the topologyInjectorDisabled and the local cluster was not defined. + Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. + Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. + Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. + Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. + Fixed Lua validator log level to be suppressed by default. + Fixed ProxyTopologyInjector cache sync race condition that caused injection failures + Fixed validation for grpc routes with extension ref filters. + +# Enhancements that improve performance. +performance improvements: | + +# Deprecated features or APIs. +deprecations: | + +# Other notable changes not covered by the above sections. +Other changes: | From e7cb7af83cd68c447adaabe59e5a0b72993e0bdb Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 9 Sep 2025 09:26:13 -0700 Subject: [PATCH 25/27] Removes reflection from RouteContext to reduce allocations (#6820) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bench: adds APIToXDS bench & small opt Signed-off-by: Takeshi Yoneda * no refect goos: darwin goarch: arm64 pkg: github.com/envoyproxy/gateway/test/gobench cpu: Apple M1 Pro │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ GatewayAPItoXDS/small-10 881.2µ ± 7% 803.4µ ± 1% -8.82% (p=0.000 n=10) GatewayAPItoXDS/medium-10 4.130m ± 26% 2.959m ± 4% -28.36% (p=0.000 n=10) GatewayAPItoXDS/large-10 5.375 ± 2% 4.553 ± 1% -15.28% (p=0.000 n=10) geomean 26.94m 22.12m -17.90% │ old.txt │ new.txt │ │ B/op │ B/op vs base │ GatewayAPItoXDS/small-10 507.2Ki ± 0% 492.9Ki ± 0% -2.83% (p=0.000 n=10) GatewayAPItoXDS/medium-10 2.545Mi ± 7% 1.954Mi ± 2% -23.21% (p=0.000 n=10) GatewayAPItoXDS/large-10 2.832Gi ± 0% 2.831Gi ± 0% ~ (p=0.529 n=10) geomean 15.40Mi 13.97Mi -9.31% │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ GatewayAPItoXDS/small-10 8.328k ± 0% 8.017k ± 0% -3.73% (p=0.000 n=10) GatewayAPItoXDS/medium-10 39.45k ± 6% 29.74k ± 2% -24.60% (p=0.000 n=10) GatewayAPItoXDS/large-10 38.75M ± 0% 38.71M ± 0% -0.11% (p=0.000 n=10) geomean 233.5k 209.8k -10.16% Signed-off-by: Takeshi Yoneda * removes garbage Signed-off-by: Takeshi Yoneda * more tests Signed-off-by: Takeshi Yoneda * more tests Signed-off-by: Takeshi Yoneda --------- Signed-off-by: Takeshi Yoneda --- internal/gatewayapi/backendtrafficpolicy.go | 2 +- internal/gatewayapi/contexts.go | 330 ++++++++++++++++---- internal/gatewayapi/envoyextensionpolicy.go | 4 +- internal/gatewayapi/helpers.go | 4 +- internal/gatewayapi/route.go | 18 +- internal/gatewayapi/securitypolicy.go | 4 +- 6 files changed, 282 insertions(+), 80 deletions(-) diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index c62d21bc9c..95510eb89d 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -48,7 +48,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(resources *resource.Resources routeMap := map[policyTargetRouteKey]*policyRouteTargetContext{} for _, route := range routes { key := policyTargetRouteKey{ - Kind: string(GetRouteType(route)), + Kind: string(route.GetRouteType()), Name: route.GetName(), Namespace: route.GetNamespace(), } diff --git a/internal/gatewayapi/contexts.go b/internal/gatewayapi/contexts.go index a8ee928abb..f9e8fb7d96 100644 --- a/internal/gatewayapi/contexts.go +++ b/internal/gatewayapi/contexts.go @@ -148,125 +148,315 @@ func (l *ListenerContext) SetTLSSecrets(tlsSecrets []*corev1.Secret) { // that can reference Gateway objects. type RouteContext interface { client.Object + GetRouteType() gwapiv1.Kind + HasRuleNames(sectionName gwapiv1.SectionName) bool + GetHostnames() []string + GetParentReferences() []gwapiv1.ParentReference + GetRouteStatus() *gwapiv1.RouteStatus + GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext + SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) } // HTTPRouteContext wraps an HTTPRoute and provides helper methods for // accessing the route's parents. type HTTPRouteContext struct { - // GatewayControllerName is the name of the Gateway API controller. - GatewayControllerName string - *gwapiv1.HTTPRoute ParentRefs map[gwapiv1.ParentReference]*RouteParentContext } +func (r *HTTPRouteContext) GetRouteType() gwapiv1.Kind { + return resource.KindHTTPRoute +} + +func (r *HTTPRouteContext) HasRuleNames(sectionName gwapiv1.SectionName) bool { + rs := r.Spec.Rules + for _, rule := range rs { + if rule.Name != nil { + if *rule.Name == sectionName { + return true + } + } + } + return false +} + +func (r *HTTPRouteContext) GetHostnames() []string { + hs := r.Spec.Hostnames + hostnames := make([]string, len(hs)) + for i := range hs { + hostnames[i] = string(hs[i]) + } + return hostnames +} + +func (r *HTTPRouteContext) GetParentReferences() []gwapiv1.ParentReference { + return r.Spec.ParentRefs +} + +func (r *HTTPRouteContext) GetRouteStatus() *gwapiv1.RouteStatus { + return &r.Status.RouteStatus +} + +func (r *HTTPRouteContext) GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + return r.ParentRefs[forParentRef] +} + +func (r *HTTPRouteContext) SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + r.ParentRefs[forParentRef] = ctx +} + // GRPCRouteContext wraps a GRPCRoute and provides helper methods for // accessing the route's parents. type GRPCRouteContext struct { - // GatewayControllerName is the name of the Gateway API controller. - GatewayControllerName string - *gwapiv1.GRPCRoute ParentRefs map[gwapiv1.ParentReference]*RouteParentContext } +func (r *GRPCRouteContext) GetRouteType() gwapiv1.Kind { + return resource.KindGRPCRoute +} + +func (r *GRPCRouteContext) HasRuleNames(sectionName gwapiv1.SectionName) bool { + rs := r.Spec.Rules + for _, rule := range rs { + if rule.Name != nil { + if *rule.Name == sectionName { + return true + } + } + } + return false +} + +func (r *GRPCRouteContext) GetHostnames() []string { + hs := r.Spec.Hostnames + hostnames := make([]string, len(hs)) + for i := range hs { + hostnames[i] = string(hs[i]) + } + return hostnames +} + +func (r *GRPCRouteContext) GetParentReferences() []gwapiv1.ParentReference { + return r.Spec.ParentRefs +} + +func (r *GRPCRouteContext) GetRouteStatus() *gwapiv1.RouteStatus { + return &r.Status.RouteStatus +} + +func (r *GRPCRouteContext) GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + return r.ParentRefs[forParentRef] +} + +func (r *GRPCRouteContext) SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + r.ParentRefs[forParentRef] = ctx +} + // TLSRouteContext wraps a TLSRoute and provides helper methods for // accessing the route's parents. type TLSRouteContext struct { - // GatewayControllerName is the name of the Gateway API controller. - GatewayControllerName string - *gwapiv1a2.TLSRoute ParentRefs map[gwapiv1.ParentReference]*RouteParentContext } +func (r *TLSRouteContext) GetRouteType() gwapiv1.Kind { + return resource.KindTLSRoute +} + +func (r *TLSRouteContext) HasRuleNames(sectionName gwapiv1.SectionName) bool { + rs := r.Spec.Rules + for _, rule := range rs { + if rule.Name != nil { + if *rule.Name == sectionName { + return true + } + } + } + return false +} + +func (r *TLSRouteContext) GetHostnames() []string { + hs := r.Spec.Hostnames + hostnames := make([]string, len(hs)) + for i := range hs { + hostnames[i] = string(hs[i]) + } + return hostnames +} + +func (r *TLSRouteContext) GetParentReferences() []gwapiv1.ParentReference { + return r.Spec.ParentRefs +} + +func (r *TLSRouteContext) GetRouteStatus() *gwapiv1.RouteStatus { + return &r.Status.RouteStatus +} + +func (r *TLSRouteContext) GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + return r.ParentRefs[forParentRef] +} + +func (r *TLSRouteContext) SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + r.ParentRefs[forParentRef] = ctx +} + // UDPRouteContext wraps a UDPRoute and provides helper methods for // accessing the route's parents. type UDPRouteContext struct { - // GatewayControllerName is the name of the Gateway API controller. - GatewayControllerName string - *gwapiv1a2.UDPRoute ParentRefs map[gwapiv1.ParentReference]*RouteParentContext } +func (r *UDPRouteContext) GetRouteType() gwapiv1.Kind { + return resource.KindUDPRoute +} + +func (r *UDPRouteContext) HasRuleNames(sectionName gwapiv1.SectionName) bool { + rs := r.Spec.Rules + for _, rule := range rs { + if rule.Name != nil { + if *rule.Name == sectionName { + return true + } + } + } + return false +} + +func (r *UDPRouteContext) GetHostnames() []string { + // UDPRoute doesn't have hostnames, return empty slice + return []string{} +} + +func (r *UDPRouteContext) GetParentReferences() []gwapiv1.ParentReference { + return r.Spec.ParentRefs +} + +func (r *UDPRouteContext) GetRouteStatus() *gwapiv1.RouteStatus { + return &r.Status.RouteStatus +} + +func (r *UDPRouteContext) GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + return r.ParentRefs[forParentRef] +} + +func (r *UDPRouteContext) SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) + } + r.ParentRefs[forParentRef] = ctx +} + +func (r *UDPRouteContext) GetParentRefs() map[gwapiv1.ParentReference]*RouteParentContext { + return r.ParentRefs +} + // TCPRouteContext wraps a TCPRoute and provides helper methods for // accessing the route's parents. type TCPRouteContext struct { - // GatewayControllerName is the name of the Gateway API controller. - GatewayControllerName string - *gwapiv1a2.TCPRoute ParentRefs map[gwapiv1.ParentReference]*RouteParentContext } -// GetRouteType returns the Kind of the Route object, HTTPRoute, -// TLSRoute, TCPRoute, UDPRoute etc. -func GetRouteType(route RouteContext) gwapiv1.Kind { - rv := reflect.ValueOf(route).Elem() - return gwapiv1.Kind(rv.FieldByName("Kind").String()) +func (r *TCPRouteContext) GetRouteType() gwapiv1.Kind { + return resource.KindTCPRoute } -// GetHostnames returns the hosts targeted by the Route object. -func GetHostnames(route RouteContext) []string { - rv := reflect.ValueOf(route).Elem() - kind := rv.FieldByName("Kind").String() - if kind == resource.KindTCPRoute || kind == resource.KindUDPRoute { - return nil +func (r *TCPRouteContext) HasRuleNames(sectionName gwapiv1.SectionName) bool { + rs := r.Spec.Rules + for _, rule := range rs { + if rule.Name != nil { + if *rule.Name == sectionName { + return true + } + } + } + return false +} + +func (r *TCPRouteContext) GetHostnames() []string { + // TCPRoute doesn't have hostnames, return empty slice + return []string{} +} + +func (r *TCPRouteContext) GetParentReferences() []gwapiv1.ParentReference { + return r.Spec.ParentRefs +} + +func (r *TCPRouteContext) GetRouteStatus() *gwapiv1.RouteStatus { + return &r.Status.RouteStatus +} + +func (r *TCPRouteContext) GetRouteParentContext(forParentRef gwapiv1.ParentReference) *RouteParentContext { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) } + return r.ParentRefs[forParentRef] +} - hs := rv.FieldByName("Spec").FieldByName("Hostnames") - hostnames := make([]string, hs.Len()) - for i := 0; i < len(hostnames); i++ { - hostnames[i] = hs.Index(i).String() +func (r *TCPRouteContext) SetRouteParentContext(forParentRef gwapiv1.ParentReference, ctx *RouteParentContext) { + if r.ParentRefs == nil { + r.ParentRefs = make(map[gwapiv1.ParentReference]*RouteParentContext) } - return hostnames + r.ParentRefs[forParentRef] = ctx +} + +// GetHostnames returns the hosts targeted by the Route object. +func GetHostnames(route RouteContext) []string { + return route.GetHostnames() } // GetParentReferences returns the ParentReference of the Route object. func GetParentReferences(route RouteContext) []gwapiv1.ParentReference { - rv := reflect.ValueOf(route).Elem() - pr := rv.FieldByName("Spec").FieldByName("ParentRefs") - return pr.Interface().([]gwapiv1.ParentReference) + return route.GetParentReferences() } // GetRouteStatus returns the RouteStatus object associated with the Route. func GetRouteStatus(route RouteContext) *gwapiv1.RouteStatus { - rv := reflect.ValueOf(route).Elem() - rs := rv.FieldByName("Status").FieldByName("RouteStatus").Interface().(gwapiv1.RouteStatus) - return &rs + return route.GetRouteStatus() } // GetRouteParentContext returns RouteParentContext by using the Route objects' ParentReference. // It creates a new RouteParentContext and add a new RouteParentStatus to the Route's Status if the ParentReference is not found. -func GetRouteParentContext(route RouteContext, forParentRef gwapiv1.ParentReference) *RouteParentContext { - rv := reflect.ValueOf(route).Elem() - pr := rv.FieldByName("ParentRefs") - - // If the ParentRefs field is nil, initialize it. - if pr.IsNil() { - mm := reflect.MakeMap(reflect.TypeOf(map[gwapiv1.ParentReference]*RouteParentContext{})) - pr.Set(mm) - } - +func GetRouteParentContext(route RouteContext, forParentRef gwapiv1.ParentReference, controllerName string) *RouteParentContext { // If the RouteParentContext is already in the RouteContext, return it. - if p := pr.MapIndex(reflect.ValueOf(forParentRef)); p.IsValid() && !p.IsZero() { - ctx := p.Interface().(*RouteParentContext) - return ctx + if existingCtx := route.GetRouteParentContext(forParentRef); existingCtx != nil { + return existingCtx } // Verify that the ParentReference is present in the Route.Spec.ParentRefs. // This is just a sanity check, the parentRef should always be present, otherwise it's a programming error. var parentRef *gwapiv1.ParentReference - specParentRefs := rv.FieldByName("Spec").FieldByName("ParentRefs") - for i := 0; i < specParentRefs.Len(); i++ { - p := specParentRefs.Index(i).Interface().(gwapiv1.ParentReference) - if reflect.DeepEqual(p, forParentRef) { + specParentRefs := route.GetParentReferences() + for _, p := range specParentRefs { + if isParentRefEqual(p, forParentRef, route.GetNamespace()) { parentRef = &p break } @@ -277,11 +467,10 @@ func GetRouteParentContext(route RouteContext, forParentRef gwapiv1.ParentRefere // Find the parent in the Route's Status. routeParentStatusIdx := -1 - statusParents := rv.FieldByName("Status").FieldByName("Parents") + routeStatus := route.GetRouteStatus() - for i := 0; i < statusParents.Len(); i++ { - p := statusParents.Index(i).FieldByName("ParentRef").Interface().(gwapiv1.ParentReference) - if isParentRefEqual(p, *parentRef, route.GetNamespace()) { + for i, parent := range routeStatus.Parents { + if isParentRefEqual(parent.ParentRef, *parentRef, route.GetNamespace()) { routeParentStatusIdx = i break } @@ -290,11 +479,11 @@ func GetRouteParentContext(route RouteContext, forParentRef gwapiv1.ParentRefere // If the parent is not found in the Route's Status, create a new RouteParentStatus and add it to the Route's Status. if routeParentStatusIdx == -1 { rParentStatus := gwapiv1a2.RouteParentStatus{ - ControllerName: gwapiv1a2.GatewayController(rv.FieldByName("GatewayControllerName").String()), + ControllerName: gwapiv1a2.GatewayController(controllerName), ParentRef: forParentRef, } - statusParents.Set(reflect.Append(statusParents, reflect.ValueOf(rParentStatus))) - routeParentStatusIdx = statusParents.Len() - 1 + routeStatus.Parents = append(routeStatus.Parents, rParentStatus) + routeParentStatusIdx = len(routeStatus.Parents) - 1 } // Also add the RouteParentContext to the RouteContext. @@ -302,9 +491,22 @@ func GetRouteParentContext(route RouteContext, forParentRef gwapiv1.ParentRefere ParentReference: parentRef, routeParentStatusIdx: routeParentStatusIdx, } - rctx := reflect.ValueOf(ctx) - rctx.Elem().FieldByName(string(GetRouteType(route))).Set(rv.Field(1)) - pr.SetMapIndex(reflect.ValueOf(forParentRef), rctx) + + // Set the appropriate route field based on the route type + switch route.GetRouteType() { + case resource.KindHTTPRoute: + ctx.HTTPRoute = route.(*HTTPRouteContext).HTTPRoute + case resource.KindGRPCRoute: + ctx.GRPCRoute = route.(*GRPCRouteContext).GRPCRoute + case resource.KindTLSRoute: + ctx.TLSRoute = route.(*TLSRouteContext).TLSRoute + case resource.KindTCPRoute: + ctx.TCPRoute = route.(*TCPRouteContext).TCPRoute + case resource.KindUDPRoute: + ctx.UDPRoute = route.(*UDPRouteContext).UDPRoute + } + + route.SetRouteParentContext(forParentRef, ctx) return ctx } diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 061898b435..b6fee16d0a 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -48,7 +48,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv routeMap := map[policyTargetRouteKey]*policyRouteTargetContext{} for _, route := range routes { key := policyTargetRouteKey{ - Kind: string(GetRouteType(route)), + Kind: string(route.GetRouteType()), Name: route.GetName(), Namespace: route.GetNamespace(), } @@ -312,7 +312,7 @@ func (t *Translator) translateEnvoyExtensionPolicyForRoute( prefix := irRoutePrefix(route) parentRefs := GetParentReferences(route) for _, p := range parentRefs { - parentRefCtx := GetRouteParentContext(route, p) + parentRefCtx := GetRouteParentContext(route, p, t.GatewayControllerName) gtwCtx := parentRefCtx.GetGateway() if gtwCtx == nil { continue diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index efa9659df4..5d65e5060c 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -385,7 +385,7 @@ func irListenerPortName(proto ir.ProtocolType, port int32) string { func irRoutePrefix(route RouteContext) string { // add a "/" at the end of the prefix to prevent mismatching routes with the // same prefix. For example, route prefix "/foo/" should not match a route "/foobar". - return fmt.Sprintf("%s/%s/%s/", strings.ToLower(string(GetRouteType(route))), route.GetNamespace(), route.GetName()) + return fmt.Sprintf("%s/%s/%s/", strings.ToLower(string(route.GetRouteType())), route.GetNamespace(), route.GetName()) } func irRouteName(route RouteContext, ruleIdx, matchIdx int) string { @@ -393,7 +393,7 @@ func irRouteName(route RouteContext, ruleIdx, matchIdx int) string { } func irTCPRouteName(route RouteContext) string { - return fmt.Sprintf("%s/%s/%s", strings.ToLower(string(GetRouteType(route))), route.GetNamespace(), route.GetName()) + return fmt.Sprintf("%s/%s/%s", strings.ToLower(string(route.GetRouteType())), route.GetNamespace(), route.GetName()) } func irUDPRouteName(route RouteContext) string { diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 7a1acc8703..040a0dc232 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -178,7 +178,7 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe irRoutes []*ir.HTTPRoute errs = &status.MultiStatusError{} ) - pattern := getStatPattern(httpRoute, parentRef) + pattern := getStatPattern(httpRoute, parentRef, t.GatewayControllerName) // process each HTTPRouteRule, generate a unique Xds IR HTTPRoute per match of the rule for ruleIdx, rule := range httpRoute.Spec.Rules { @@ -632,7 +632,7 @@ func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRe irRoutes []*ir.HTTPRoute errs = &status.MultiStatusError{} ) - pattern := getStatPattern(grpcRoute, parentRef) + pattern := getStatPattern(grpcRoute, parentRef, t.GatewayControllerName) // compute matches, filters, backends for ruleIdx, rule := range grpcRoute.Spec.Rules { @@ -872,7 +872,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route irListener := xdsIR[irKey].GetHTTPListener(irListenerName(listener)) if irListener != nil { - if GetRouteType(route) == resource.KindGRPCRoute { + if route.GetRouteType() == resource.KindGRPCRoute { irListener.IsHTTP2 = true } irListener.Routes = append(irListener.Routes, perHostRoutes...) @@ -1364,7 +1364,7 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour func (t *Translator) processDestination(name string, backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext, resources *resource.Resources, ) (ds *ir.DestinationSetting, unstructuredRef *ir.UnstructuredRef, err status.Error) { - routeType := GetRouteType(route) + routeType := route.GetRouteType() weight := uint32(1) backendRef := GetBackendRef(backendRefContext) if backendRef.Weight != nil { @@ -1388,7 +1388,7 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe } var envoyProxy *egv1a1.EnvoyProxy - gatewayCtx := GetRouteParentContext(route, *parentRef.ParentReference).GetGateway() + gatewayCtx := GetRouteParentContext(route, *parentRef.ParentReference, t.GatewayControllerName).GetGateway() if gatewayCtx != nil { envoyProxy = gatewayCtx.envoyProxy } @@ -1716,7 +1716,7 @@ func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteCont } relevantRoute = true - parentRefCtx := GetRouteParentContext(routeContext, parentRef) + parentRefCtx := GetRouteParentContext(routeContext, parentRef, t.GatewayControllerName) // Reset conditions since they will be recomputed during translation parentRefCtx.ResetConditions(routeContext) @@ -1735,7 +1735,7 @@ func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteCont var allowedListeners []*ListenerContext for _, listener := range selectedListeners { - acceptedKind := GetRouteType(routeContext) + acceptedKind := routeContext.GetRouteType() if listener.AllowsKind(gwapiv1.RouteGroupKind{Group: GroupPtr(gwapiv1.GroupName), Kind: acceptedKind}) && listener.AllowsNamespace(resources.GetNamespace(routeContext.GetNamespace())) { allowedListeners = append(allowedListeners, listener) @@ -2051,10 +2051,10 @@ func backendAppProtocolToIRAppProtocol(ap egv1a1.AppProtocolType, defaultProtoco } } -func getStatPattern(routeContext RouteContext, parentRef *RouteParentContext) string { +func getStatPattern(routeContext RouteContext, parentRef *RouteParentContext, controllerName string) string { var pattern string var envoyProxy *egv1a1.EnvoyProxy - gatewayCtx := GetRouteParentContext(routeContext, *parentRef.ParentReference).GetGateway() + gatewayCtx := GetRouteParentContext(routeContext, *parentRef.ParentReference, controllerName).GetGateway() if gatewayCtx != nil { envoyProxy = gatewayCtx.envoyProxy } diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 7fc9a3286b..8981f8802e 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -65,7 +65,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security routeMap := map[policyTargetRouteKey]*policyRouteTargetContext{} for _, route := range routes { key := policyTargetRouteKey{ - Kind: string(GetRouteType(route)), + Kind: string(route.GetRouteType()), Name: route.GetName(), Namespace: route.GetNamespace(), } @@ -648,7 +648,7 @@ func (t *Translator) translateSecurityPolicyForRoute( prefix := irRoutePrefix(route) parentRefs := GetParentReferences(route) for _, p := range parentRefs { - parentRefCtx := GetRouteParentContext(route, p) + parentRefCtx := GetRouteParentContext(route, p, t.GatewayControllerName) gtwCtx := parentRefCtx.GetGateway() if gtwCtx == nil { continue From 8c133f0df561049312d01d05aa626ec054905355 Mon Sep 17 00:00:00 2001 From: zirain Date: Tue, 16 Sep 2025 11:04:18 +0800 Subject: [PATCH 26/27] [release/v1.5] 1.5.1 release-notes Signed-off-by: zirain --- VERSION | 2 +- release-notes/v1.5.1.yaml | 25 +++++++----- site/content/en/news/releases/notes/v1.5.1.md | 39 +++++++++++++++++++ tools/make/tools.mk | 2 +- 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 site/content/en/news/releases/notes/v1.5.1.md diff --git a/VERSION b/VERSION index 2e7bd91085..53b5bbb127 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.5.0 +v1.5.1 diff --git a/release-notes/v1.5.1.yaml b/release-notes/v1.5.1.yaml index 0cbbda2ccc..e2e856d86d 100644 --- a/release-notes/v1.5.1.yaml +++ b/release-notes/v1.5.1.yaml @@ -5,27 +5,32 @@ breaking changes: | # Updates addressing vulnerabilities, security flaws, or compliance requirements. security updates: | + Updated distroless image to resolve glibc CVEs. + Bumped Go version to 1.24.7. # New features or capabilities added in this release. new features: | bug fixes: | - Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. - Fixed maxAcceptPerSocketEvent being ignored in ClientTrafficPolicy. - Fixed the topologyInjectorDisabled and the local cluster was not defined. - Fixed log formatting of improper key-value pairs to avoid DPANIC in controller-runtime logger. - Fixed handling of context-related transient errors to prevent incorrect state reconciliation and unintended behavior. - Fixed the controller cannot read the EnvoyProxy attached gatewayclass only. - Fixed indexer and controller crashing when BackendTrafficPolicy has a redirect response override. - Fixed Lua validator log level to be suppressed by default. - Fixed ProxyTopologyInjector cache sync race condition that caused injection failures - Fixed validation for grpc routes with extension ref filters. + Fixed cluster stat name generation to use lowercase names. + Resolved nil pointer dereference in configmap indexer. + Corrected log formatting to avoid DPANIC errors. + Improved context error handling throughout the codebase. + Fixed issues with topology injector and local cluster configuration. + Updated HTTP status code validation maximum from 600 to 599. + Enhanced proxy protocol filter placement as first listener filter. # Enhancements that improve performance. performance improvements: | + Optimized pod cache operations. + Reduced DeepCopy operations in gateway-api layer. + Removed reflection from RouteContext to reduce memory allocations. # Deprecated features or APIs. deprecations: | # Other notable changes not covered by the above sections. Other changes: | + Updated BackendTrafficPolicy compression configuration validation. + Improved image validation regex for container images. + Enhanced targetRef selection for target selectors. diff --git a/site/content/en/news/releases/notes/v1.5.1.md b/site/content/en/news/releases/notes/v1.5.1.md new file mode 100644 index 0000000000..6b0992f246 --- /dev/null +++ b/site/content/en/news/releases/notes/v1.5.1.md @@ -0,0 +1,39 @@ +--- +title: "v1.5.1" +publishdate: 2024-09-16 +--- + +Date: September 16, 2024 + +## Breaking changes +- + +## Security updates +- Updated distroless image to resolve glibc CVEs. +- Bumped Go version to 1.24.7. + +## New features +- + +## Bug fixes +- Fixed cluster stat name generation to use lowercase names. +- Resolved nil pointer dereference in configmap indexer. +- Corrected log formatting to avoid DPANIC errors. +- Improved context error handling throughout the codebase. +- Fixed issues with topology injector and local cluster configuration. +- Updated HTTP status code validation maximum from 600 to 599. +- Enhanced proxy protocol filter placement as first listener filter. + +## Performance improvements +- Optimized pod cache operations. +- Reduced DeepCopy operations in gateway-api layer. +- Removed reflection from RouteContext to reduce memory allocations. + +## Deprecations +- + +## Other changes +- Updated BackendTrafficPolicy compression configuration validation. +- Improved image validation regex for container images. +- Enhanced targetRef selection for target selectors. + diff --git a/tools/make/tools.mk b/tools/make/tools.mk index 10dba5f079..cf6da50fbc 100644 --- a/tools/make/tools.mk +++ b/tools/make/tools.mk @@ -19,7 +19,7 @@ tools/release-notes-docs = $(tools.bindir)/release-notes-docs $(tools.bindir)/%.d/venv: $(tools.srcdir)/%/requirements.txt mkdir -p $(@D) python3 -m venv $@ - $@/bin/pip3 install -r $< || (rm -rf $@; exit 1) + $@/bin/pip3 install --trusted-host pypi.org --trusted-host files.pythonhosted.org --disable-pip-version-check -r $< || (rm -rf $@; exit 1) $(tools.bindir)/%: $(tools.bindir)/%.d/venv @if [ -e $(tools.srcdir)/$*/$*.sh ]; then \ ln -sf ../../$(tools.srcdir)/$*/$*.sh $@; \ From b05d90a457d00a43f252e8efa5dd914f00da6dff Mon Sep 17 00:00:00 2001 From: zirain Date: Tue, 16 Sep 2025 20:23:06 +0800 Subject: [PATCH 27/27] fix benchmark job (#6979) Signed-off-by: zirain --- test/benchmark/config/nighthawk-client.yaml | 3 ++- test/benchmark/config/nighthawk-test-server.yaml | 2 +- test/benchmark/suite/suite.go | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/benchmark/config/nighthawk-client.yaml b/test/benchmark/config/nighthawk-client.yaml index a9621d3fb7..35553eda6c 100644 --- a/test/benchmark/config/nighthawk-client.yaml +++ b/test/benchmark/config/nighthawk-client.yaml @@ -11,6 +11,7 @@ spec: - name: nighthawk-client image: envoyproxy/nighthawk-dev:latest imagePullPolicy: IfNotPresent - args: ["nighthawk_client"] # Fill-up args at runtime + command: + - /usr/local/bin/nighthawk_client restartPolicy: Never backoffLimit: 3 diff --git a/test/benchmark/config/nighthawk-test-server.yaml b/test/benchmark/config/nighthawk-test-server.yaml index dfd91aae46..75fa0bfbd6 100644 --- a/test/benchmark/config/nighthawk-test-server.yaml +++ b/test/benchmark/config/nighthawk-test-server.yaml @@ -19,7 +19,7 @@ spec: - name: nighthawk-server image: envoyproxy/nighthawk-dev:latest imagePullPolicy: IfNotPresent - args: ["nighthawk_test_server", "-c", "/etc/test-server-config/nighthawk-test-server-config.yaml"] + args: ["-c", "/etc/test-server-config/nighthawk-test-server-config.yaml"] ports: - containerPort: 8080 volumeMounts: diff --git a/test/benchmark/suite/suite.go b/test/benchmark/suite/suite.go index e8a045bec1..7066b081bd 100644 --- a/test/benchmark/suite/suite.go +++ b/test/benchmark/suite/suite.go @@ -191,7 +191,7 @@ func (b *BenchmarkTestSuite) Benchmark(t *testing.T, ctx context.Context, jobNam for i := 1; i <= host; i++ { requestHeaders = append(requestHeaders, "Host: "+fmt.Sprintf(hostnamePattern, i)) } - jobNN, err := b.createBenchmarkClientJob(ctx, jobName, gatewayHostPort, requestHeaders) + jobNN, err := b.createBenchmarkClientJob(t, jobName, gatewayHostPort, requestHeaders) if err != nil { return nil, err } @@ -251,7 +251,7 @@ func (b *BenchmarkTestSuite) Benchmark(t *testing.T, ctx context.Context, jobNam return report, nil } -func (b *BenchmarkTestSuite) createBenchmarkClientJob(ctx context.Context, name, gatewayHostPort string, requestHeaders []string) (*types.NamespacedName, error) { +func (b *BenchmarkTestSuite) createBenchmarkClientJob(t *testing.T, name, gatewayHostPort string, requestHeaders []string) (*types.NamespacedName, error) { job := b.BenchmarkClientJob.DeepCopy() job.SetName(name) job.SetLabels(map[string]string{ @@ -262,7 +262,8 @@ func (b *BenchmarkTestSuite) createBenchmarkClientJob(ctx context.Context, name, container := &job.Spec.Template.Spec.Containers[0] container.Args = append(container.Args, runtimeArgs...) - if err := b.CreateResource(ctx, job); err != nil { + t.Logf("Creating benchmark client job: %s with args: %v", name, job) + if err := b.CreateResource(t.Context(), job); err != nil { return nil, err }