diff --git a/changelog/v1.19.11/fix-readiness-probe.yaml b/changelog/v1.19.11/fix-readiness-probe.yaml new file mode 100644 index 00000000000..e19c7e63932 --- /dev/null +++ b/changelog/v1.19.11/fix-readiness-probe.yaml @@ -0,0 +1,6 @@ +changelog: +- type: FIX + issueLink: https://github.com/solo-io/gloo/issues/10541 + resolvesIssue: false + description: Fixes a bug where the envoy pod passes the readiness probe before receving the xds config. + diff --git a/projects/gateway2/helm/gloo-gateway/templates/gateway/proxy-deployment.yaml b/projects/gateway2/helm/gloo-gateway/templates/gateway/proxy-deployment.yaml index 3291d5e9a4c..4ad47f084e7 100644 --- a/projects/gateway2/helm/gloo-gateway/templates/gateway/proxy-deployment.yaml +++ b/projects/gateway2/helm/gloo-gateway/templates/gateway/proxy-deployment.yaml @@ -439,45 +439,8 @@ data: metadata: role: gloo-kube-gateway-api~{{ $gateway.gatewayNamespace }}~{{ $gateway.gatewayNamespace }}-{{ $gateway.gatewayName | default (include "gloo-gateway.gateway.fullname" .) }} static_resources: - listeners: - - name: readiness_listener - address: - socket_address: { address: 0.0.0.0, port_value: 8082 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - codec_type: AUTO - route_config: - name: main_route - virtual_hosts: - - name: local_service - domains: ["*"] - routes: - - match: - path: "/ready" - headers: - - name: ":method" - string_match: - exact: GET - route: - cluster: admin_port_cluster - http_filters: -{{- if $gateway.readinessProbe }} - - name: envoy.filters.http.health_check - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck - pass_through_mode: false - headers: - - name: ":path" - exact_match: "/envoy-hc" -{{- end }}{{/*if $gateway.readinessProbe*/}} - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router {{- if $statsConfig.enabled }} + listeners: - name: prometheus_listener address: socket_address: @@ -526,6 +489,8 @@ data: - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router +{{- else}} + listeners: [] {{- end }} {{/* if $gateway.stats.enabled */}} clusters: - name: xds_cluster diff --git a/projects/gateway2/setup/testdata/failover-default-diffns-out.yaml b/projects/gateway2/setup/testdata/failover-default-diffns-out.yaml index 6afb2268618..5aaef0db4ea 100644 --- a/projects/gateway2/setup/testdata/failover-default-diffns-out.yaml +++ b/projects/gateway2/setup/testdata/failover-default-diffns-out.yaml @@ -208,6 +208,59 @@ listeners: upgradeConfigs: - upgradeType: websocket name: http +- address: + socketAddress: + address: '::' + ipv4Compat: true + portValue: 8082 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.fault + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + - name: envoy.filters.http.cors + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.local_ratelimit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit + stage: 3 + statPrefix: http_local_ratelimit + - name: envoy.filters.http.grpc_web + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - exactMatch: /envoy-hc + name: :path + passThroughMode: false + - name: io.solo.transformation + typedConfig: + '@type': type.googleapis.com/envoy.api.v2.filter.http.FilterTransformations + - name: envoy.filters.http.csrf + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy + filterEnabled: + defaultValue: {} + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: readiness_listener-routes + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + name: readiness_listener routes: - ignorePortInHostMatching: true name: http-routes-14610285773269467959 @@ -222,3 +275,9 @@ routes: route: cluster: kube-svc:gwtest-reviews-8080_gwtest clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR +- ignorePortInHostMatching: true + name: readiness_listener-routes + virtualHosts: + - domains: + - '*' + name: local_service diff --git a/projects/gateway2/setup/testdata/failover-default-out.yaml b/projects/gateway2/setup/testdata/failover-default-out.yaml index 1fc614124ef..87163453e46 100644 --- a/projects/gateway2/setup/testdata/failover-default-out.yaml +++ b/projects/gateway2/setup/testdata/failover-default-out.yaml @@ -208,6 +208,59 @@ listeners: upgradeConfigs: - upgradeType: websocket name: http +- address: + socketAddress: + address: '::' + ipv4Compat: true + portValue: 8082 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.fault + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + - name: envoy.filters.http.cors + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.local_ratelimit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit + stage: 3 + statPrefix: http_local_ratelimit + - name: envoy.filters.http.grpc_web + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - exactMatch: /envoy-hc + name: :path + passThroughMode: false + - name: io.solo.transformation + typedConfig: + '@type': type.googleapis.com/envoy.api.v2.filter.http.FilterTransformations + - name: envoy.filters.http.csrf + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy + filterEnabled: + defaultValue: {} + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: readiness_listener-routes + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + name: readiness_listener routes: - ignorePortInHostMatching: true name: http-routes-14610285773269467959 @@ -222,3 +275,9 @@ routes: route: cluster: kube-svc:gwtest-reviews-8080_gwtest clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR +- ignorePortInHostMatching: true + name: readiness_listener-routes + virtualHosts: + - domains: + - '*' + name: local_service diff --git a/projects/gateway2/setup/testdata/failover-out.yaml b/projects/gateway2/setup/testdata/failover-out.yaml index 2ae0816b5c5..b8e01482ad8 100644 --- a/projects/gateway2/setup/testdata/failover-out.yaml +++ b/projects/gateway2/setup/testdata/failover-out.yaml @@ -207,6 +207,59 @@ listeners: upgradeConfigs: - upgradeType: websocket name: http +- address: + socketAddress: + address: '::' + ipv4Compat: true + portValue: 8082 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.fault + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + - name: envoy.filters.http.cors + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.local_ratelimit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit + stage: 3 + statPrefix: http_local_ratelimit + - name: envoy.filters.http.grpc_web + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - exactMatch: /envoy-hc + name: :path + passThroughMode: false + - name: io.solo.transformation + typedConfig: + '@type': type.googleapis.com/envoy.api.v2.filter.http.FilterTransformations + - name: envoy.filters.http.csrf + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy + filterEnabled: + defaultValue: {} + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: readiness_listener-routes + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + name: readiness_listener routes: - ignorePortInHostMatching: true name: http-routes-14610285773269467959 @@ -221,3 +274,9 @@ routes: route: cluster: kube-svc:gwtest-reviews-8080_gwtest clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR +- ignorePortInHostMatching: true + name: readiness_listener-routes + virtualHosts: + - domains: + - '*' + name: local_service diff --git a/projects/gateway2/setup/testdata/happypath-out.yaml b/projects/gateway2/setup/testdata/happypath-out.yaml index e08ad861c17..5d1b8fa4fc3 100644 --- a/projects/gateway2/setup/testdata/happypath-out.yaml +++ b/projects/gateway2/setup/testdata/happypath-out.yaml @@ -157,6 +157,59 @@ listeners: upgradeConfigs: - upgradeType: websocket name: http +- address: + socketAddress: + address: '::' + ipv4Compat: true + portValue: 8082 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.fault + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + - name: envoy.filters.http.cors + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.local_ratelimit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit + stage: 3 + statPrefix: http_local_ratelimit + - name: envoy.filters.http.grpc_web + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - exactMatch: /envoy-hc + name: :path + passThroughMode: false + - name: io.solo.transformation + typedConfig: + '@type': type.googleapis.com/envoy.api.v2.filter.http.FilterTransformations + - name: envoy.filters.http.csrf + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy + filterEnabled: + defaultValue: {} + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: readiness_listener-routes + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + name: readiness_listener routes: - ignorePortInHostMatching: true name: http-routes-14610285773269467959 @@ -171,3 +224,9 @@ routes: route: cluster: kube-svc:gwtest-reviews-8080_gwtest clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR +- ignorePortInHostMatching: true + name: readiness_listener-routes + virtualHosts: + - domains: + - '*' + name: local_service diff --git a/projects/gateway2/setup/testdata/listeneropts-out.yaml b/projects/gateway2/setup/testdata/listeneropts-out.yaml index 9e16b451e59..f537ecfb7b5 100644 --- a/projects/gateway2/setup/testdata/listeneropts-out.yaml +++ b/projects/gateway2/setup/testdata/listeneropts-out.yaml @@ -205,6 +205,59 @@ listeners: - upgradeType: websocket name: other perConnectionBufferLimitBytes: 42000 +- address: + socketAddress: + address: '::' + ipv4Compat: true + portValue: 8082 + filterChains: + - filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + httpFilters: + - name: envoy.filters.http.fault + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault + - name: envoy.filters.http.cors + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.local_ratelimit + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit + stage: 3 + statPrefix: http_local_ratelimit + - name: envoy.filters.http.grpc_web + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.health_check + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck + headers: + - exactMatch: /envoy-hc + name: :path + passThroughMode: false + - name: io.solo.transformation + typedConfig: + '@type': type.googleapis.com/envoy.api.v2.filter.http.FilterTransformations + - name: envoy.filters.http.csrf + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy + filterEnabled: + defaultValue: {} + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: readiness_listener-routes + statPrefix: http + upgradeConfigs: + - upgradeType: websocket + name: readiness_listener routes: - ignorePortInHostMatching: true name: http-routes-14610285773269467959 @@ -232,3 +285,9 @@ routes: route: cluster: kube-svc:gwtest-reviews-8080_gwtest clusterNotFoundResponseCode: INTERNAL_SERVER_ERROR +- ignorePortInHostMatching: true + name: readiness_listener-routes + virtualHosts: + - domains: + - '*' + name: local_service diff --git a/projects/gateway2/translator/gateway_translator.go b/projects/gateway2/translator/gateway_translator.go index 4182d6976ab..6beb0cad4dd 100644 --- a/projects/gateway2/translator/gateway_translator.go +++ b/projects/gateway2/translator/gateway_translator.go @@ -91,6 +91,8 @@ func (t *translator) TranslateProxy( reporter, ) + listeners = listener.AppendHealthCheckListener(listeners) + return &v1.Proxy{ Metadata: proxyMetadata(gateway, writeNamespace), Listeners: listeners, diff --git a/projects/gateway2/translator/listener/gateway_listener_translator.go b/projects/gateway2/translator/listener/gateway_listener_translator.go index 2c7a1620224..ae7938bb9b3 100644 --- a/projects/gateway2/translator/listener/gateway_listener_translator.go +++ b/projects/gateway2/translator/listener/gateway_listener_translator.go @@ -15,6 +15,7 @@ import ( gwv1 "sigs.k8s.io/gateway-api/apis/v1" gwv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + edgegwutils "github.com/solo-io/gloo/projects/gateway/pkg/translator/utils" "github.com/solo-io/gloo/projects/gateway2/ports" "github.com/solo-io/gloo/projects/gateway2/query" "github.com/solo-io/gloo/projects/gateway2/reports" @@ -26,6 +27,7 @@ import ( "github.com/solo-io/gloo/projects/gateway2/translator/sslutils" "github.com/solo-io/gloo/projects/gateway2/wellknown" v1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1" + "github.com/solo-io/gloo/projects/gloo/pkg/api/v1/options/healthcheck" "github.com/solo-io/gloo/projects/gloo/pkg/api/v1/ssl" "github.com/solo-io/gloo/projects/gloo/pkg/utils" ) @@ -786,3 +788,46 @@ func makeVhostName( ) string { return utils.SanitizeForEnvoy(ctx, parentName+"~"+domain, "vHost") } + +// AppendHealthCheckListener appends a readiness listener with the health check plugin defined on it +// and returns the updated listener list +func AppendHealthCheckListener(listeners []*v1.Listener) []*v1.Listener { + return append(listeners, GenerateHealthCheckListener()) +} + +// GenerateHealthCheckListener returns a readiness listener with the health check plugin defined on it +func GenerateHealthCheckListener() *v1.Listener { + healthCheckOption := &v1.HttpListenerOptions{ + HealthCheck: &healthcheck.HealthCheck{ + Path: "/envoy-hc", + }, + } + httpOptionsByName := map[string]*v1.HttpListenerOptions{} + httpOptionsRef := edgegwutils.HashAndStoreHttpOptions(healthCheckOption, httpOptionsByName) + + return &v1.Listener{ + Name: "readiness_listener", + BindAddress: "::", + BindPort: 8082, + + ListenerType: &v1.Listener_AggregateListener{ + AggregateListener: &v1.AggregateListener{ + HttpResources: &v1.AggregateListener_HttpResources{ + VirtualHosts: map[string]*v1.VirtualHost{ + "local_service": { + Name: "local_service", + Domains: []string{"*"}}, + }, + HttpOptions: httpOptionsByName, + }, + HttpFilterChains: []*v1.AggregateListener_HttpFilterChain{{ + VirtualHostRefs: []string{"local_service"}, + HttpOptionsRef: httpOptionsRef, + }}, + TcpListeners: nil, + }, + }, + Options: nil, // Listener options will be added by policy plugins + RouteOptions: nil, + } +} diff --git a/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_plugin_test.go b/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_plugin_test.go index 42c0616b979..df347076893 100644 --- a/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_plugin_test.go +++ b/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_plugin_test.go @@ -1,4 +1,4 @@ -package httplisteneroptions +package httplisteneroptions_test import ( "context" @@ -12,6 +12,7 @@ import ( solokubev1 "github.com/solo-io/gloo/projects/gateway/pkg/api/v1/kube/apis/gateway.solo.io/v1" gwquery "github.com/solo-io/gloo/projects/gateway2/query" "github.com/solo-io/gloo/projects/gateway2/translator/plugins" + "github.com/solo-io/gloo/projects/gateway2/translator/plugins/httplisteneroptions" httplisoptquery "github.com/solo-io/gloo/projects/gateway2/translator/plugins/httplisteneroptions/query" "github.com/solo-io/gloo/projects/gateway2/translator/testutils" "github.com/solo-io/gloo/projects/gateway2/wellknown" @@ -27,7 +28,7 @@ var _ = Describe("HttpListenerOptions Plugin", func() { Describe("Attaching HttpListenerOptions via policy attachment", func() { var ( deps []client.Object - plugin *plugin + plugin plugins.ListenerPlugin ctx context.Context listenerCtx *plugins.ListenerContext @@ -67,7 +68,7 @@ var _ = Describe("HttpListenerOptions Plugin", func() { JustBeforeEach(func() { fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, httplisoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin = NewPlugin(gwQueries, fakeClient) + plugin = httplisteneroptions.NewPlugin(gwQueries, fakeClient) }) When("HttpListenerOptions exist in the same namespace and are attached correctly", func() { diff --git a/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_suite_test.go b/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_suite_test.go index 6d75b50a7c4..fe601d2ae83 100644 --- a/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_suite_test.go +++ b/projects/gateway2/translator/plugins/httplisteneroptions/httplistener_options_suite_test.go @@ -1,4 +1,4 @@ -package httplisteneroptions +package httplisteneroptions_test import ( "testing" diff --git a/projects/gateway2/translator/plugins/listeneroptions/listener_options_plugin_test.go b/projects/gateway2/translator/plugins/listeneroptions/listener_options_plugin_test.go index 569b76b2092..c1fc9faa181 100644 --- a/projects/gateway2/translator/plugins/listeneroptions/listener_options_plugin_test.go +++ b/projects/gateway2/translator/plugins/listeneroptions/listener_options_plugin_test.go @@ -1,4 +1,4 @@ -package listeneroptions +package listeneroptions_test import ( "context" @@ -12,6 +12,7 @@ import ( solokubev1 "github.com/solo-io/gloo/projects/gateway/pkg/api/v1/kube/apis/gateway.solo.io/v1" gwquery "github.com/solo-io/gloo/projects/gateway2/query" "github.com/solo-io/gloo/projects/gateway2/translator/plugins" + "github.com/solo-io/gloo/projects/gateway2/translator/plugins/listeneroptions" lisoptquery "github.com/solo-io/gloo/projects/gateway2/translator/plugins/listeneroptions/query" "github.com/solo-io/gloo/projects/gateway2/translator/testutils" "github.com/solo-io/gloo/projects/gateway2/wellknown" @@ -26,7 +27,7 @@ var _ = Describe("ListenerOptions Plugin", func() { Describe("Attaching ListenerOptions via policy attachment", func() { var ( deps []client.Object - plugin *plugin + plugin plugins.ListenerPlugin ctx context.Context listenerCtx *plugins.ListenerContext @@ -59,7 +60,7 @@ var _ = Describe("ListenerOptions Plugin", func() { JustBeforeEach(func() { fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, lisoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin = NewPlugin(gwQueries, fakeClient) + plugin = listeneroptions.NewPlugin(gwQueries, fakeClient) }) When("ListenerOptions exist in the same namespace and are attached correctly", func() { diff --git a/projects/gateway2/translator/plugins/listeneroptions/listener_options_suite_test.go b/projects/gateway2/translator/plugins/listeneroptions/listener_options_suite_test.go index 0dc072fa0f9..bbad477c61e 100644 --- a/projects/gateway2/translator/plugins/listeneroptions/listener_options_suite_test.go +++ b/projects/gateway2/translator/plugins/listeneroptions/listener_options_suite_test.go @@ -1,4 +1,4 @@ -package listeneroptions +package listeneroptions_test import ( "testing" diff --git a/projects/gateway2/translator/plugins/routeoptions/route_options_plugin.go b/projects/gateway2/translator/plugins/routeoptions/route_options_plugin.go index 03eea5fb2be..4b02500d097 100644 --- a/projects/gateway2/translator/plugins/routeoptions/route_options_plugin.go +++ b/projects/gateway2/translator/plugins/routeoptions/route_options_plugin.go @@ -34,9 +34,9 @@ import ( ) const ( - // policyOverrideAnnotation can be set by parent routes to allow child routes to override + // PolicyOverrideAnnotation can be set by parent routes to allow child routes to override // all (wildcard *) or specific fields (comma separated field names) in RouteOptions inherited from the parent route. - policyOverrideAnnotation = "delegation.gateway.solo.io/enable-policy-overrides" + PolicyOverrideAnnotation = "delegation.gateway.solo.io/enable-policy-overrides" // wildcardField is used to enable overriding all fields in RouteOptions inherited from the parent route. wildcardField = "*" @@ -103,7 +103,7 @@ func (p *plugin) ApplyRoutePlugin( return nil } - merged, OptionsMergeResult := mergeOptionsForRoute(ctx, routeCtx.HTTPRoute, routeOptions, outputRoute.GetOptions()) + merged, OptionsMergeResult := MergeOptionsForRoute(ctx, routeCtx.HTTPRoute, routeOptions, outputRoute.GetOptions()) if OptionsMergeResult == glooutils.OptionsMergedNone { // No existing options merged into 'sources', so set the 'sources' on the outputRoute routeutils.SetRouteSources(outputRoute, sources) @@ -122,7 +122,7 @@ func (p *plugin) ApplyRoutePlugin( return nil } -func mergeOptionsForRoute( +func MergeOptionsForRoute( ctx context.Context, route *gwv1.HTTPRoute, dst, src *gloov1.RouteOptions, @@ -141,13 +141,13 @@ func mergeOptionsForRoute( // // By default, parent options (routeOptions) are preferred, unless the parent explicitly // enabled child routes (outputRoute.Options) to override parent options. - fieldsStr, delegatedPolicyOverride := route.Annotations[policyOverrideAnnotation] + fieldsStr, delegatedPolicyOverride := route.Annotations[PolicyOverrideAnnotation] if delegatedPolicyOverride { delegatedFieldsToOverride := parseDelegationFieldOverrides(fieldsStr) if delegatedFieldsToOverride.Len() == 0 { // Invalid annotation value, so log an error but enforce the default behavior of preferring the parent options. contextutils.LoggerFrom(ctx).Errorf("invalid value %q for annotation %s on route %s; must be %s or a comma-separated list of field names", - fieldsStr, policyOverrideAnnotation, client.ObjectKeyFromObject(route), wildcardField) + fieldsStr, PolicyOverrideAnnotation, client.ObjectKeyFromObject(route), wildcardField) } else { fieldsAllowedToOverride = delegatedFieldsToOverride } diff --git a/projects/gateway2/translator/plugins/routeoptions/route_options_plugin_test.go b/projects/gateway2/translator/plugins/routeoptions/route_options_plugin_test.go index a0497cb53e4..47f31a61d30 100644 --- a/projects/gateway2/translator/plugins/routeoptions/route_options_plugin_test.go +++ b/projects/gateway2/translator/plugins/routeoptions/route_options_plugin_test.go @@ -1,4 +1,4 @@ -package routeoptions +package routeoptions_test import ( "context" @@ -19,6 +19,7 @@ import ( gwquery "github.com/solo-io/gloo/projects/gateway2/query" "github.com/solo-io/gloo/projects/gateway2/reports" "github.com/solo-io/gloo/projects/gateway2/translator/plugins" + "github.com/solo-io/gloo/projects/gateway2/translator/plugins/routeoptions" rtoptquery "github.com/solo-io/gloo/projects/gateway2/translator/plugins/routeoptions/query" "github.com/solo-io/gloo/projects/gateway2/translator/testutils" "github.com/solo-io/gloo/projects/gateway2/translator/translatorutils" @@ -90,7 +91,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{routeOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) rtCtx := &plugins.RouteContext{ HTTPRoute: &gwv1.HTTPRoute{}, @@ -130,7 +131,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) route := routeWithFilter() reportsMap := reports.NewReportMap() @@ -160,7 +161,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -225,7 +226,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedRouteOptionOmitNamespace()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -304,7 +305,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -322,7 +323,7 @@ var _ = Describe("RouteOptionsPlugin", func() { plugin.ApplyRoutePlugin(ctx, routeCtx, outputRoute) err := plugin.ApplyStatusPlugin(ctx, statusCtx) - Expect(err).To(MatchError(ContainSubstring(ReadingRouteOptionErrStr))) + Expect(err).To(MatchError(ContainSubstring(routeoptions.ReadingRouteOptionErrStr))) }) }) @@ -331,7 +332,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{routeOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) rtCtx := &plugins.RouteContext{ HTTPRoute: &gwv1.HTTPRoute{}, @@ -353,7 +354,7 @@ var _ = Describe("RouteOptionsPlugin", func() { plugin.ApplyRoutePlugin(context.Background(), rtCtx, outputRoute) err := plugin.ApplyStatusPlugin(ctx, statusCtx) - Expect(err).To(MatchError(ContainSubstring(ReadingRouteOptionErrStr))) + Expect(err).To(MatchError(ContainSubstring(routeoptions.ReadingRouteOptionErrStr))) }) }) }) @@ -364,7 +365,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedRouteOption(), attachedRouteOptionBefore()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -446,7 +447,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{firstOpt, secondOpt, thirdOpt} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -508,7 +509,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{nonAttachedRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -555,7 +556,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -602,7 +603,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{attachedInvalidRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -708,7 +709,7 @@ var _ = Describe("RouteOptionsPlugin", func() { deps := []client.Object{routeOption(), attachedRouteOption()} fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, rtoptquery.IterateIndices) gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) - plugin := NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) + plugin := routeoptions.NewPlugin(gwQueries, fakeClient, routeOptionCollection, statusReporter) ctx := context.Background() routeCtx := &plugins.RouteContext{ @@ -736,7 +737,7 @@ var _ = Describe("RouteOptionsPlugin", func() { var _ = DescribeTable("mergeOptionsForRoute", func(route *gwv1.HTTPRoute, dst, src *v1.RouteOptions, expectedOptions *v1.RouteOptions, expectedResult glooutils.OptionsMergeResult) { - mergedOptions, result := mergeOptionsForRoute(context.TODO(), route, dst, src) + mergedOptions, result := routeoptions.MergeOptionsForRoute(context.TODO(), route, dst, src) Expect(proto.Equal(mergedOptions, expectedOptions)).To(BeTrue()) Expect(result).To(Equal(expectedResult)) }, @@ -771,7 +772,7 @@ var _ = DescribeTable("mergeOptionsForRoute", Entry("override dst options with annotation: full override", &gwv1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{policyOverrideAnnotation: "*"}, + Annotations: map[string]string{routeoptions.PolicyOverrideAnnotation: "*"}, }, }, &v1.RouteOptions{ @@ -802,7 +803,7 @@ var _ = DescribeTable("mergeOptionsForRoute", Entry("override dst options with annotation: partial override", &gwv1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{policyOverrideAnnotation: "*"}, + Annotations: map[string]string{routeoptions.PolicyOverrideAnnotation: "*"}, }, }, &v1.RouteOptions{ @@ -835,7 +836,7 @@ var _ = DescribeTable("mergeOptionsForRoute", Entry("override dst options with annotation: no override", &gwv1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{policyOverrideAnnotation: "*"}, + Annotations: map[string]string{routeoptions.PolicyOverrideAnnotation: "*"}, }, }, &v1.RouteOptions{ @@ -858,7 +859,7 @@ var _ = DescribeTable("mergeOptionsForRoute", Entry("override dst options with annotation: specific fields", &gwv1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{policyOverrideAnnotation: "faults,timeout"}, + Annotations: map[string]string{routeoptions.PolicyOverrideAnnotation: "faults,timeout"}, }, }, &v1.RouteOptions{ diff --git a/projects/gateway2/translator/plugins/routeoptions/route_options_suite_test.go b/projects/gateway2/translator/plugins/routeoptions/route_options_suite_test.go index 77a18c96cf4..cfe0a89447c 100644 --- a/projects/gateway2/translator/plugins/routeoptions/route_options_suite_test.go +++ b/projects/gateway2/translator/plugins/routeoptions/route_options_suite_test.go @@ -1,4 +1,4 @@ -package routeoptions +package routeoptions_test import ( "testing" diff --git a/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_plugin_test.go b/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_plugin_test.go index 4a983cf95a3..95849c73508 100644 --- a/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_plugin_test.go +++ b/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_plugin_test.go @@ -1,4 +1,4 @@ -package virtualhostoptions +package virtualhostoptions_test import ( "context" @@ -17,6 +17,7 @@ import ( gwquery "github.com/solo-io/gloo/projects/gateway2/query" "github.com/solo-io/gloo/projects/gateway2/translator/plugins" "github.com/solo-io/gloo/projects/gateway2/translator/plugins/utils" + "github.com/solo-io/gloo/projects/gateway2/translator/plugins/virtualhostoptions" vhoptquery "github.com/solo-io/gloo/projects/gateway2/translator/plugins/virtualhostoptions/query" "github.com/solo-io/gloo/projects/gateway2/translator/testutils" "github.com/solo-io/gloo/projects/gateway2/translator/translatorutils" @@ -39,12 +40,17 @@ var _ = Describe("VirtualHostOptions Plugin", func() { Describe("Attaching VirtualHostOptions via policy attachment", func() { var ( deps []client.Object - plugin *plugin + plugin plugins.ListenerPlugin ctx context.Context listenerCtx *plugins.ListenerContext outputListener *v1.Listener expectedOptions *v1.VirtualHostOptions + + fakeClient client.Client + gwQueries gwquery.GatewayQueries + vhOptionCollection krt.StaticSingleton[*solokubev1.VirtualHostOption] + statusReporter reporter.StatusReporter ) BeforeEach(func() { ctx = context.Background() @@ -79,17 +85,17 @@ var _ = Describe("VirtualHostOptions Plugin", func() { } }) JustBeforeEach(func() { - fakeClient := testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, vhoptquery.IterateIndices) - gwQueries := testutils.BuildGatewayQueriesWithClient(fakeClient) + fakeClient = testutils.BuildIndexedFakeClient(deps, gwquery.IterateIndices, vhoptquery.IterateIndices) + gwQueries = testutils.BuildGatewayQueriesWithClient(fakeClient) resourceClientFactory := &factory.MemoryResourceClientFactory{ Cache: memory.NewInMemoryResourceCache(), } vhOptionClient, _ := sologatewayv1.NewVirtualHostOptionClient(ctx, resourceClientFactory) - vhOptionCollection := krt.NewStatic[*gatewaykubev1.VirtualHostOption](nil, true) + vhOptionCollection = krt.NewStatic[*gatewaykubev1.VirtualHostOption](nil, true) statusClient := statusutils.GetStatusClientForNamespace("gloo-system") - statusReporter := reporter.NewReporter(defaults.KubeGatewayReporter, statusClient, vhOptionClient.BaseClient()) - plugin = NewPlugin(gwQueries, fakeClient, vhOptionCollection.AsCollection(), statusReporter) + statusReporter = reporter.NewReporter(defaults.KubeGatewayReporter, statusClient, vhOptionClient.BaseClient()) + plugin = virtualhostoptions.NewPlugin(gwQueries, fakeClient, vhOptionCollection.AsCollection(), statusReporter) }) When("outListener is not an AggregateListener", func() { BeforeEach(func() { @@ -202,6 +208,8 @@ var _ = Describe("VirtualHostOptions Plugin", func() { When("There is an error reading the VirtualHostOptions", func() { It("errors out", func() { + plugin := virtualhostoptions.NewPlugin(gwQueries, fakeClient, vhOptionCollection.AsCollection(), statusReporter) + plugin.ApplyListenerPlugin(ctx, listenerCtx, outputListener) statusCtx := &plugins.StatusContext{ @@ -217,7 +225,7 @@ var _ = Describe("VirtualHostOptions Plugin", func() { } err := plugin.ApplyStatusPlugin(ctx, statusCtx) - Expect(err).To(MatchError(ContainSubstring(ReadingVirtualHostOptionErrStr))) + Expect(err).To(MatchError(ContainSubstring(virtualhostoptions.ReadingVirtualHostOptionErrStr))) }) }) }) diff --git a/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_suite_test.go b/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_suite_test.go index 30cbadc0fe4..6cc61b002f5 100644 --- a/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_suite_test.go +++ b/projects/gateway2/translator/plugins/virtualhostoptions/virtualhost_options_suite_test.go @@ -1,4 +1,4 @@ -package virtualhostoptions +package virtualhostoptions_test import ( "testing" diff --git a/projects/gateway2/translator/testutils/test_file_loader.go b/projects/gateway2/translator/testutils/test_file_loader.go index 097e810f295..ab655db645e 100644 --- a/projects/gateway2/translator/testutils/test_file_loader.go +++ b/projects/gateway2/translator/testutils/test_file_loader.go @@ -14,6 +14,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/rotisserie/eris" "github.com/solo-io/gloo/pkg/utils/protoutils" + "github.com/solo-io/gloo/projects/gateway2/translator/listener" v1 "github.com/solo-io/gloo/projects/gloo/pkg/api/v1" "github.com/ghodss/yaml" @@ -162,6 +163,8 @@ func ReadProxyFromFile(filename string) (*v1.Proxy, error) { if err := protoutils.UnmarshalYaml(data, &proxy); err != nil { return nil, eris.Wrapf(err, "parsing proxy from file") } + // Append the healthcheck listener here to avoid adding it to every file + proxy.Listeners = listener.AppendHealthCheckListener(proxy.GetListeners()) return &proxy, nil }