From 44d133d6e4c48a65635c860554098f604eaa7bf7 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Mon, 11 Nov 2024 13:00:59 -0800 Subject: [PATCH 01/25] Trying to validate config using STDIN and /dev/fd/0 --- projects/envoyinit/pkg/runner/run.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index 1fe96f24383..15db00e711f 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -3,6 +3,7 @@ package runner import ( "bytes" "context" + "fmt" "log" "os" "syscall" @@ -30,7 +31,9 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) - validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-yaml", bootstrapConfig, "-l", "critical", "--log-format", "%v") + validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") + validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) + logger.Warnf(fmt.Sprintf("Running envoy with command: %v, len: %d", validateCmd, len(bootstrapConfig))) if err := validateCmd.Run(); err != nil { if os.IsNotExist(err) { // log a warning and return nil; will allow users to continue to run Gloo locally without From 43d5512edfdae120cc772625863bb16bf5ffedda Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Mon, 11 Nov 2024 14:32:19 -0800 Subject: [PATCH 02/25] Adding change log --- changelog/v1.18.0-beta34/validate-large-configs.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changelog/v1.18.0-beta34/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta34/validate-large-configs.yaml b/changelog/v1.18.0-beta34/validate-large-configs.yaml new file mode 100644 index 00000000000..f65effabfd7 --- /dev/null +++ b/changelog/v1.18.0-beta34/validate-large-configs.yaml @@ -0,0 +1,10 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/solo-projects/issues/7089 + resolvesIssue: false + description: >- + Fix the validation of large configurations. + Previously, the configuration was being passed as an argument and we were + seeing `argument list too long`. + This change passes the configuration as a file instead, using STDIN (/dev/fd/0) + avoiding the need to store the file on disk. \ No newline at end of file From 4ee4b2034b46648113d013c6f27780b7554714d6 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Tue, 12 Nov 2024 11:16:57 -0800 Subject: [PATCH 03/25] Fixed for tests and new test for large configs --- Makefile | 5 +- projects/envoyinit/pkg/runner/run.go | 1 + test/kube2e/README.md | 3 +- test/kube2e/gateway/gateway_suite_test.go | 5 +- .../gloo/artifacts/large-configuration.yaml | 1313 +++++++++++++++++ test/kube2e/gloo/gloo_suite_test.go | 5 +- test/kube2e/gloo/large_configuration_test.go | 43 + 7 files changed, 1369 insertions(+), 6 deletions(-) create mode 100644 test/kube2e/gloo/artifacts/large-configuration.yaml create mode 100644 test/kube2e/gloo/large_configuration_test.go diff --git a/Makefile b/Makefile index 254ebbaa73d..d8acd11012f 100644 --- a/Makefile +++ b/Makefile @@ -253,9 +253,9 @@ install-protoc: .PHONY: test test: ## Run all tests, or only run the test package at {TEST_PKG} if it is specified - $(GINKGO_ENV) $(DEPSGOBIN)/ginkgo -ldflags=$(LDFLAGS) \ + CLUSTER_NAME=${CLUSTER_NAME} $(GINKGO_ENV) $(DEPSGOBIN)/ginkgo -ldflags=$(LDFLAGS) \ $(GINKGO_FLAGS) $(GINKGO_REPORT_FLAGS) $(GINKGO_USER_FLAGS) \ - $(TEST_PKG) + $(TEST_PKG) # https://go.dev/blog/cover#heat-maps .PHONY: test-with-coverage @@ -290,7 +290,6 @@ run-hashicorp-e2e-tests: test run-kube-e2e-tests: TEST_PKG = ./test/kube2e/$(KUBE2E_TESTS) ## Run the Kubernetes E2E Tests in the {KUBE2E_TESTS} package run-kube-e2e-tests: test - #---------------------------------------------------------------------------------- # Go Tests #---------------------------------------------------------------------------------- diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index 15db00e711f..9466f4ae544 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -31,6 +31,7 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) + //validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-yaml", bootstrapConfig, "-l", "critical", "--log-format", "%v") validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) logger.Warnf(fmt.Sprintf("Running envoy with command: %v, len: %d", validateCmd, len(bootstrapConfig))) diff --git a/test/kube2e/README.md b/test/kube2e/README.md index e7778808d82..662dec992df 100644 --- a/test/kube2e/README.md +++ b/test/kube2e/README.md @@ -65,7 +65,7 @@ To run the regression tests, your kubeconfig file must point to a running Kubern Use the same command that CI relies on: ```bash -KUBE2E_TESTS= make run-kube-e2e-tests +CLUSTER_NAME=solo-test-cluster KUBE2E_TESTS= make run-kube-e2e-tests ``` #### Test Environment Variables @@ -78,6 +78,7 @@ The below table contains the environment variables that can be used to configure | WAIT_ON_FAIL | 0 | Set to 1 to prevent Ginkgo from cleaning up the Gloo Edge installation in case of failure. Useful to exec into inspect resources created by the test. A command to resume the test run (and thus clean up resources) will be logged to the output. | | TEAR_DOWN | false | Set to true to uninstall Gloo after the test suite completes | | RELEASED_VERSION | '' | Used by nightlies to tests a specific released version. 'LATEST' will find the latest release | +| CLUSTER_NAME | kind | Used to control which Kind cluster to run the tests inside | #### Common Test Errors `getting Helm chart version: expected a single entry with name [gloo], found: 5`\ diff --git a/test/kube2e/gateway/gateway_suite_test.go b/test/kube2e/gateway/gateway_suite_test.go index f98a9db07b3..34a4c2d5439 100644 --- a/test/kube2e/gateway/gateway_suite_test.go +++ b/test/kube2e/gateway/gateway_suite_test.go @@ -72,8 +72,11 @@ func StartTestHelper() { installGloo() } + clusterName := os.Getenv("CLUSTER_NAME") + Expect(clusterName).NotTo(BeEmpty(), "CLUSTER_NAME must be set") + // We rely on the "new" kubernetes/e2e setup code, since it incorporates controller-runtime logging setup - clusterContext := cluster.MustKindContext("kind") + clusterContext := cluster.MustKindContext(clusterName) resourceClientset, err = kube2e.NewKubeResourceClientSet(ctx, clusterContext.RestConfig) Expect(err).NotTo(HaveOccurred(), "can create kube resource client set") diff --git a/test/kube2e/gloo/artifacts/large-configuration.yaml b/test/kube2e/gloo/artifacts/large-configuration.yaml new file mode 100644 index 00000000000..dce91ebb80c --- /dev/null +++ b/test/kube2e/gloo/artifacts/large-configuration.yaml @@ -0,0 +1,1313 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: httpbin + namespace: default +--- +apiVersion: v1 +kind: Service +metadata: + name: httpbin + namespace: default + labels: + app: httpbin + service: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 8080 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + serviceAccountName: httpbin + containers: + - name: httpbin + image: docker.io/mccutchen/go-httpbin:v2.6.0 + imagePullPolicy: IfNotPresent + command: [ go-httpbin ] + args: + - "-port" + - "8080" + - "-max-duration" + - "600s" # override default 10s + ports: + - containerPort: 8080 + # Include curl container for e2e testing, allows sending traffic mediated by the proxy sidecar + - name: curl + image: curlimages/curl:7.83.1 + resources: + requests: + cpu: "100m" + limits: + cpu: "200m" + imagePullPolicy: IfNotPresent + command: + - "tail" + - "-f" + - "/dev/null" + - name: hey + image: gcr.io/solo-public/docs/hey:0.1.4 + imagePullPolicy: IfNotPresent +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualService +metadata: + name: httpbin-1 + namespace: gloo-system +spec: + virtualHost: + domains: + - httpbin-1.example.io + optionsConfigRefs: + delegateOptions: + - name: cors-company + namespace: gloo-system + - name: jwt-validation-company + namespace: gloo-system + - name: jwt-decode-company + namespace: gloo-system + routes: + - directResponseAction: + body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' + status: 451 + matchers: + - headers: + - name: x-something-country-blocked + value: country_not_allowed + prefix: / + - matchers: + - exact: /gql/v2/healthcheck + options: + autoHostRewrite: true + prefixRewrite: /healthcheck + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-user-token + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /ip + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /get + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /headers + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /status + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /user-agent + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /cookies + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /base64 + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - invertMatch: true + name: x-something-api-key + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% + else %}{{ body() }}{% endif%}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: ^$ + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: .+ + prefix: /gql/v2 + options: + autoHostRewrite: true + extauth: + configRef: + name: something + namespace: gloo-system + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% + else %}{{ context() }}{% endif %}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + headers: + x-something-profile-id: + text: web-app-ssr + x-something-user-id: + text: web-app-ssr + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualService +metadata: + name: httpbin-2 + namespace: gloo-system +spec: + virtualHost: + domains: + - httpbin-2.example.io + optionsConfigRefs: + delegateOptions: + - name: cors-company + namespace: gloo-system + - name: jwt-validation-company + namespace: gloo-system + - name: jwt-decode-company + namespace: gloo-system + routes: + - directResponseAction: + body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' + status: 451 + matchers: + - headers: + - name: x-something-country-blocked + value: country_not_allowed + prefix: / + - matchers: + - exact: /gql/v2/healthcheck + options: + autoHostRewrite: true + prefixRewrite: /healthcheck + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-user-token + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /ip + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /get + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /headers + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /status + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /user-agent + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /cookies + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /base64 + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - invertMatch: true + name: x-something-api-key + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% + else %}{{ body() }}{% endif%}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: ^$ + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: .+ + prefix: /gql/v2 + options: + autoHostRewrite: true + extauth: + configRef: + name: something + namespace: gloo-system + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% + else %}{{ context() }}{% endif %}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + headers: + x-something-profile-id: + text: web-app-ssr + x-something-user-id: + text: web-app-ssr + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualService +metadata: + name: httpbin-3 + namespace: gloo-system +spec: + virtualHost: + domains: + - httpbin-3.example.io + optionsConfigRefs: + delegateOptions: + - name: cors-company + namespace: gloo-system + - name: jwt-validation-company + namespace: gloo-system + - name: jwt-decode-company + namespace: gloo-system + routes: + - directResponseAction: + body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' + status: 451 + matchers: + - headers: + - name: x-something-country-blocked + value: country_not_allowed + prefix: / + - matchers: + - exact: /gql/v2/healthcheck + options: + autoHostRewrite: true + prefixRewrite: /healthcheck + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-user-token + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /ip + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /get + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /headers + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /status + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /user-agent + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /cookies + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /base64 + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - invertMatch: true + name: x-something-api-key + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% + else %}{{ body() }}{% endif%}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: ^$ + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: .+ + prefix: /gql/v2 + options: + autoHostRewrite: true + extauth: + configRef: + name: something + namespace: gloo-system + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% + else %}{{ context() }}{% endif %}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + headers: + x-something-profile-id: + text: web-app-ssr + x-something-user-id: + text: web-app-ssr + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system +--- +apiVersion: gloo.solo.io/v1 +kind: Upstream +metadata: + name: default-httpbin-8000 + namespace: default +spec: + discoveryMetadata: {} + kube: + serviceName: httpbin + serviceNamespace: default + servicePort: 8000 +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualService +metadata: + name: httpbin-4 + namespace: gloo-system +spec: + virtualHost: + domains: + - httpbin-4.example.io + optionsConfigRefs: + delegateOptions: + - name: cors-company + namespace: gloo-system + - name: jwt-validation-company + namespace: gloo-system + - name: jwt-decode-company + namespace: gloo-system + routes: + - directResponseAction: + body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' + status: 451 + matchers: + - headers: + - name: x-something-country-blocked + value: country_not_allowed + prefix: / + - matchers: + - exact: /gql/v2/healthcheck + options: + autoHostRewrite: true + prefixRewrite: /healthcheck + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-user-token + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /ip + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /get + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /headers + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /status + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /user-agent + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /cookies + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - prefix: /base64 + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: gloo-system + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - invertMatch: true + name: x-something-api-key + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% + else %}{{ body() }}{% endif%}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: ^$ + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: .+ + prefix: /gql/v2 + options: + autoHostRewrite: true + extauth: + configRef: + name: something + namespace: gloo-system + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% + else %}{{ context() }}{% endif %}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + headers: + x-something-profile-id: + text: web-app-ssr + x-something-user-id: + text: web-app-ssr + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + namespace: gloo-system +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: cors-company + namespace: gloo-system +spec: + options: + cors: + allowCredentials: true + allowHeaders: + - origin, + - x-requested-with, + - accept, + - content-type, + - authorization, + - x-something-api-key, + - x-something-device-type, + - x-something-platform, + - x-something-app-version, + - x-something-platform-version, + - x-something-default-language, + - x-something-country-code-override, + - x-something-user-token, + - x-something-install-id, + - x-something-profile-id, + - x-something-install-date, + - x-something-context-override, + - x-something-is-kid-profile, + - x-something-cosed, + - x-px-block-error, + - x-something-debug, + - x-something-token-key-id + allowMethods: + - GET + - PUT + - POST + - DELETE + - PATCH + allowOrigin: + - http://localhost:3000 + allowOriginRegex: + - https://*.company.com + exposeHeaders: + - '*' + maxAge: 3628800s +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: jwt-decode-company + namespace: gloo-system +spec: + options: + stagedTransformations: + early: + requestTransforms: + - clearRouteCache: true + requestTransformation: + transformationTemplate: + advancedTemplates: true + extractors: + bearer: + header: authorization + regex: Bearer.(.*)\.(.*)\.(.*) + subgroup: 2 + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + body: + text: '{% if existsIn(context(), "video")%}{"video":{% set seriesMediaIdValue="default" + %}{% set nextEpisodeMediaIdValue="default" %}{% set page = at(context(), + "video") %}{ {% for key, value in page %} {% if at(loop, "is_first") + and key != "seriesMediaId" and key != "mediaId" and key != "nextEpisodeMediaId" + %}{% set first_key=key %}{% set first_value=value %}{% endif %}{% + if key == "mediaId" and substring(value, 0, 21) == "transmission:matchid:" + %}"mediaId":"video:mcp:unexpected-live-match",{% else %}{% if + key == "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% endif + %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif %}{% + endif %}{% if key == "seriesMediaId" %}{% set seriesMediaIdValue=value + %}{% endif %}{% if key == "nextEpisodeMediaId" %}{% set nextEpisodeMediaIdValue=value + %}{% endif %}{% if key != "seriesMediaId" and key != "nextEpisodeMediaId" + and key != "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% + endif %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif + %}{% endfor %}"{{first_key}}":{% if not isNumber(first_value) + %}"{% endif %}{{first_value}}{% if not isNumber(first_value) %}"{% + endif %}{% if seriesMediaIdValue != "default" and seriesMediaIdValue + != "" %},"seriesMediaId":{% if not isNumber(seriesMediaIdValue)%}"{% + endif %}{{seriesMediaIdValue}}{% if not isNumber(seriesMediaIdValue) + %}"{% endif %}{% endif %}{% if nextEpisodeMediaIdValue != "default" + and seriesMediaIdValue != "default" and seriesMediaIdValue != + "" %},"nextEpisodeMediaId":{% if not isNumber(nextEpisodeMediaIdValue)%}"{% + endif %}{{nextEpisodeMediaIdValue}}{% if not isNumber(nextEpisodeMediaIdValue) + %}"{% endif %}{% endif %} }} {% else %}{{ context() }}{% endif + %}' + extractors: + country: + header: x-something-country-code + regex: (AR|BO|CL|CO|CR|DO|EC|GT|HN|MX|NI|PA|PE|PR|PY|SV|US|UY|VE) + subgroup: 1 + profile: + header: profile-id + regex: .*?"id.{3}(\w*[-_\w*]*).* + subgroup: 1 + profile-extractor: + header: profile-extended + regex: .*?"id.{3}(\w*[-_\w*]*).* + subgroup: 1 + sub: + header: sub-claim + regex: ^(.*\|)?(.*)$ + subgroup: 2 + subscription-id: + header: x-something-subscription-info + regex: .*"subscriptionId".*?"([^"]+)".* + subgroup: 1 + subscription-id-user-token: + header: x-something-subscription-info-user-token + regex: .*"subscriptionId".*?"([^"]+)".* + subgroup: 1 + subscription-tier: + header: x-something-subscription-info-user-token + regex: .*"subscriptionTier.{3}(\w*).* + subgroup: 1 + headers: + x-something-country-blocked: + text: '{% if extraction("country") == "" %}country_not_allowed{% + endif %}' + x-something-install-id: + text: '{% if request_header("x-something-install-id") != "" %}{{ request_header("x-something-install-id") + }}{% else %}{% if header("x-something-install-id-claim") != "" %}{{ + header("x-something-install-id-claim") }}{% else %}asdfasdf{% + endif %}{% endif %}' + x-something-plan-group: + text: '{% if extraction("subscription-id") == "" %}default{% else + %}{%if extraction("subscription-id") in ["something-sv-web-prepaid-7d", + "something-gt-web-prepaid-7d", "something-gt-web-prepaid-15d", "something-gt-web-prepaid-30d", + "something-hd-web-prepaid-7d", "something-hd-web-prepaid-15d", "something-hd-web-prepaid-30d", + "something-ng-web-prepaid-7d", "something-ng-web-prepaid-15d","something-ng-web-prepaid-30d", + "something-pn-web-prepaid-7d", "something-hn-web-prepaid-standalone-7d"] + %}something-restricted{% else %}default{% endif %}{% endif%}' + x-something-plan-ids: + text: '{% if extraction("subscription-id") == "" %}{{ extraction("subscription-id-user-token") + }}{% else %}{{ extraction("subscription-id") }}{% endif %}' + x-something-profile-id: + text: '{% if request_header("x-something-profile-id") != "" %}{% set + a = false %}{% for num in range(length(header("x-something-available-profile-ids")) + / 36 ) %}{% if substring(header("x-something-available-profile-ids"), + num * 36 + num , 36) == request_header("x-something-profile-id") %}{{ + request_header("x-something-profile-id") }}{% set a = true %}{% endif + %}{% endfor %}{% if a == false %}{{ request_header("x-something-profile-id") + }}{% endif %}{% else %} {% if header("x-iss") == "identity-api.self.something.com"%} {{ + extraction("profile") }}{% else %}{% if extraction("profile-extractor") + != "" %}{{ extraction("profile-extractor") }}{% else %}{{ extraction("user-token-profile-id") + }}{% endif%}{% endif %}{% endif %}' + x-something-subscription-plan-tier: + text: '{{ extraction("subscription-tier") }}' + x-something-user-id: + text: '{{ extraction("sub") }}' + headersToRemove: + - authorization + - x-something-subscription-info + - x-something-install-id-claim + - profile-extended + - x-something-subscription-info-user-token +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: jwt-validation-company + namespace: gloo-system +spec: + options: +--- +apiVersion: gateway.solo.io/v1 +kind: RouteOption +metadata: + name: jwt-route-ip + namespace: gloo-system +spec: + options: + autoHostRewrite: true + prefixRewrite: /get + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header("server") == "Google Frontend" %}{{ body() }}{% else %}{% if header(":status") == "401" %}{"error":"Invalid Token","errorCode":"INVALID_TOKEN","message":"Invalid Token","statusCode":403}{% else if header(":status") == "429" %}{"status":"fail","data":{"error":"QUOTA_EXCEEDED","path": "{{ request_header(":path") }}" }}{% else %}{{ body() }}{% endif %}{% endif %}' + headers: + :status: + text: '{% if header("server") == "Google Frontend" %}{{ header(":status") }}{% else %}{% if header(":status") == "401" %}403{% else if header(":status") == "429" %}450{% else %}{{ header(":status") }}{% endif %}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s diff --git a/test/kube2e/gloo/gloo_suite_test.go b/test/kube2e/gloo/gloo_suite_test.go index e8f13f8bc7f..ba68c66bd43 100644 --- a/test/kube2e/gloo/gloo_suite_test.go +++ b/test/kube2e/gloo/gloo_suite_test.go @@ -72,8 +72,11 @@ var _ = BeforeSuite(func() { installGloo() } + clusterName := os.Getenv("CLUSTER_NAME") + Expect(clusterName).NotTo(BeEmpty(), "CLUSTER_NAME must be set") + // We rely on the "new" kubernetes/e2e setup code, since it incorporates controller-runtime logging setup - clusterContext := cluster.MustKindContext("kind") + clusterContext := cluster.MustKindContext(clusterName) resourceClientset, err = kube2e.NewKubeResourceClientSet(ctx, clusterContext.RestConfig) Expect(err).NotTo(HaveOccurred(), "can create kube resource client set") diff --git a/test/kube2e/gloo/large_configuration_test.go b/test/kube2e/gloo/large_configuration_test.go new file mode 100644 index 00000000000..80b72dbd3f2 --- /dev/null +++ b/test/kube2e/gloo/large_configuration_test.go @@ -0,0 +1,43 @@ +package gloo_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/solo-io/gloo/projects/gloo/pkg/api/v1/gloosnapshot" + + "github.com/solo-io/solo-kit/pkg/api/v1/clients" +) + +var _ = Describe("Large configuration", func() { + var ( + glooResources *gloosnapshot.ApiSnapshot + ) + + BeforeEach(func() { + glooResources = &gloosnapshot.ApiSnapshot{} + }) + + JustBeforeEach(func() { + err := snapshotWriter.WriteSnapshot(glooResources, clients.WriteOpts{ + Ctx: ctx, + OverwriteExisting: false, + }) + Expect(err).NotTo(HaveOccurred()) + }) + + JustAfterEach(func() { + err := snapshotWriter.DeleteSnapshot(glooResources, clients.DeleteOpts{ + Ctx: ctx, + IgnoreNotExist: true, + }) + Expect(err).NotTo(HaveOccurred()) + }) + + // We have a customer that was experiencing issue with full validation of a large configuration. + // They were seeing an `argument list too long` error. + // This test is to ensure that we can create a large configuration that is representative of their use case. + It("should be able to create a large configuration", func() { + err := testHelper.ApplyFile(ctx, testHelper.RootDir+"/test/kube2e/gloo/artifacts/large-configuration.yaml") + Expect(err).NotTo(HaveOccurred()) + }) +}) From 9f50557a268cf6a383532ec6bce0f627e1220c60 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Tue, 12 Nov 2024 11:19:56 -0800 Subject: [PATCH 04/25] Minor adjustments --- Makefile | 3 ++- projects/envoyinit/pkg/runner/run.go | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index fec09b1f05c..defe7edeb18 100644 --- a/Makefile +++ b/Makefile @@ -255,7 +255,7 @@ install-protoc: test: ## Run all tests, or only run the test package at {TEST_PKG} if it is specified CLUSTER_NAME=${CLUSTER_NAME} $(GINKGO_ENV) $(DEPSGOBIN)/ginkgo -ldflags=$(LDFLAGS) \ $(GINKGO_FLAGS) $(GINKGO_REPORT_FLAGS) $(GINKGO_USER_FLAGS) \ - $(TEST_PKG) + $(TEST_PKG) # https://go.dev/blog/cover#heat-maps .PHONY: test-with-coverage @@ -290,6 +290,7 @@ run-hashicorp-e2e-tests: test run-kube-e2e-tests: TEST_PKG = ./test/kube2e/$(KUBE2E_TESTS) ## Run the Kubernetes E2E Tests in the {KUBE2E_TESTS} package run-kube-e2e-tests: test + #---------------------------------------------------------------------------------- # Go Tests #---------------------------------------------------------------------------------- diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index 9466f4ae544..e7a671e9744 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -3,7 +3,6 @@ package runner import ( "bytes" "context" - "fmt" "log" "os" "syscall" @@ -31,10 +30,8 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) - //validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-yaml", bootstrapConfig, "-l", "critical", "--log-format", "%v") validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) - logger.Warnf(fmt.Sprintf("Running envoy with command: %v, len: %d", validateCmd, len(bootstrapConfig))) if err := validateCmd.Run(); err != nil { if os.IsNotExist(err) { // log a warning and return nil; will allow users to continue to run Gloo locally without From 81d9d2c0ab770f265c376a24ca80d6ee850a8fbe Mon Sep 17 00:00:00 2001 From: Ryan Olds Date: Tue, 12 Nov 2024 12:48:24 -0800 Subject: [PATCH 05/25] Update changelog/v1.18.0-beta34/validate-large-configs.yaml Co-authored-by: Nathan Fudenberg --- changelog/v1.18.0-beta34/validate-large-configs.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/changelog/v1.18.0-beta34/validate-large-configs.yaml b/changelog/v1.18.0-beta34/validate-large-configs.yaml index f65effabfd7..fe46cdd4420 100644 --- a/changelog/v1.18.0-beta34/validate-large-configs.yaml +++ b/changelog/v1.18.0-beta34/validate-large-configs.yaml @@ -3,8 +3,7 @@ changelog: issueLink: https://github.com/solo-io/solo-projects/issues/7089 resolvesIssue: false description: >- - Fix the validation of large configurations. - Previously, the configuration was being passed as an argument and we were - seeing `argument list too long`. + Fix the validation of large configurations when using envoy validation. + Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. This change passes the configuration as a file instead, using STDIN (/dev/fd/0) avoiding the need to store the file on disk. \ No newline at end of file From 3306ab196ac19351b0502e73162c2ccd15918d4a Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Tue, 12 Nov 2024 12:49:07 -0800 Subject: [PATCH 06/25] Remove uneeded env var setting --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index defe7edeb18..7f0d6fc2940 100644 --- a/Makefile +++ b/Makefile @@ -253,7 +253,7 @@ install-protoc: .PHONY: test test: ## Run all tests, or only run the test package at {TEST_PKG} if it is specified - CLUSTER_NAME=${CLUSTER_NAME} $(GINKGO_ENV) $(DEPSGOBIN)/ginkgo -ldflags=$(LDFLAGS) \ + $(GINKGO_ENV) $(DEPSGOBIN)/ginkgo -ldflags=$(LDFLAGS) \ $(GINKGO_FLAGS) $(GINKGO_REPORT_FLAGS) $(GINKGO_USER_FLAGS) \ $(TEST_PKG) From 32c8ab18369358d673498021a1710b82428d305f Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Tue, 12 Nov 2024 13:20:14 -0800 Subject: [PATCH 07/25] Adjsuted how we work out the cluster context in kube2e tests --- test/kube2e/gateway/gateway_suite_test.go | 7 +++---- test/kube2e/gloo/gloo_suite_test.go | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/test/kube2e/gateway/gateway_suite_test.go b/test/kube2e/gateway/gateway_suite_test.go index 34a4c2d5439..60998adee87 100644 --- a/test/kube2e/gateway/gateway_suite_test.go +++ b/test/kube2e/gateway/gateway_suite_test.go @@ -22,6 +22,7 @@ import ( "github.com/solo-io/gloo/test/helpers" "github.com/solo-io/gloo/test/kube2e" "github.com/solo-io/gloo/test/kube2e/helper" + testruntime "github.com/solo-io/gloo/test/kubernetes/testutils/runtime" skhelpers "github.com/solo-io/solo-kit/test/helpers" . "github.com/onsi/ginkgo/v2" @@ -72,11 +73,9 @@ func StartTestHelper() { installGloo() } - clusterName := os.Getenv("CLUSTER_NAME") - Expect(clusterName).NotTo(BeEmpty(), "CLUSTER_NAME must be set") - // We rely on the "new" kubernetes/e2e setup code, since it incorporates controller-runtime logging setup - clusterContext := cluster.MustKindContext(clusterName) + runtimeContext := testruntime.NewContext() + clusterContext := cluster.MustKindContext(runtimeContext.ClusterName) resourceClientset, err = kube2e.NewKubeResourceClientSet(ctx, clusterContext.RestConfig) Expect(err).NotTo(HaveOccurred(), "can create kube resource client set") diff --git a/test/kube2e/gloo/gloo_suite_test.go b/test/kube2e/gloo/gloo_suite_test.go index ba68c66bd43..f269f3ddf1c 100644 --- a/test/kube2e/gloo/gloo_suite_test.go +++ b/test/kube2e/gloo/gloo_suite_test.go @@ -23,6 +23,7 @@ import ( "github.com/solo-io/gloo/test/helpers" "github.com/solo-io/gloo/test/kube2e" "github.com/solo-io/gloo/test/kube2e/helper" + testruntime "github.com/solo-io/gloo/test/kubernetes/testutils/runtime" glootestutils "github.com/solo-io/gloo/test/testutils" "github.com/solo-io/go-utils/testutils" @@ -72,11 +73,9 @@ var _ = BeforeSuite(func() { installGloo() } - clusterName := os.Getenv("CLUSTER_NAME") - Expect(clusterName).NotTo(BeEmpty(), "CLUSTER_NAME must be set") - // We rely on the "new" kubernetes/e2e setup code, since it incorporates controller-runtime logging setup - clusterContext := cluster.MustKindContext(clusterName) + runtimeContext := testruntime.NewContext() + clusterContext := cluster.MustKindContext(runtimeContext.ClusterName) resourceClientset, err = kube2e.NewKubeResourceClientSet(ctx, clusterContext.RestConfig) Expect(err).NotTo(HaveOccurred(), "can create kube resource client set") From 743097566751f24977a4203c8f6f7dd3043ebcc7 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Tue, 12 Nov 2024 14:02:04 -0800 Subject: [PATCH 08/25] Moved kubernetes e2e test --- test/kube2e/README.md | 4 ++++ .../validation/full_envoy_validation/suite.go | 11 +++++++++++ .../valid-resources}/large-configuration.yaml | 0 test/kubernetes/e2e/features/validation/types.go | 5 +++++ 4 files changed, 20 insertions(+) rename test/{kube2e/gloo/artifacts => kubernetes/e2e/features/validation/testdata/valid-resources}/large-configuration.yaml (100%) diff --git a/test/kube2e/README.md b/test/kube2e/README.md index 662dec992df..d8d49e8b4b4 100644 --- a/test/kube2e/README.md +++ b/test/kube2e/README.md @@ -1,4 +1,8 @@ # Kubernetes End-to-End tests + +> These are our legacy Kubernetes E2E tests. We are migrating them to `../kubernetes/e2e`. Create new E2E tests there +> using the new framework. + See the [developer kube-e2e testing guide](/devel/testing/kube-e2e-tests.md) for more information about the philosophy of these tests. *Note: All commands should be run from the root directory of the Gloo repository* diff --git a/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go b/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go index 6fa18a103f3..f626bceb23b 100644 --- a/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go +++ b/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go @@ -72,3 +72,14 @@ func (s *testingSuite) TestRejectInvalidTransformation() { s.Assert().Contains(output, "Failed to parse response template: Failed to parse "+ "header template ':status': [inja.exception.parser_error] (at 1:92) expected statement close, got '%'") } + +// TestLargeConfiguration checks webhook accepts large configuration when fullEnvoyValidation=true +func (s *testingSuite) TestLargeConfiguration() { + s.T().Cleanup(func() { + err := s.testInstallation.Actions.Kubectl().DeleteFileSafe(s.ctx, validation.LargeConfiguration, "-n", s.testInstallation.Metadata.InstallNamespace) + s.Assertions.NoError(err, "can delete large configuration") + }) + + err := s.testInstallation.Actions.Kubectl().ApplyFile(s.ctx, validation.LargeConfiguration, "-n", s.testInstallation.Metadata.InstallNamespace) + s.Assert().NoError(err) +} diff --git a/test/kube2e/gloo/artifacts/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml similarity index 100% rename from test/kube2e/gloo/artifacts/large-configuration.yaml rename to test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml diff --git a/test/kubernetes/e2e/features/validation/types.go b/test/kubernetes/e2e/features/validation/types.go index e0870e79733..926b6146f1d 100644 --- a/test/kubernetes/e2e/features/validation/types.go +++ b/test/kubernetes/e2e/features/validation/types.go @@ -7,6 +7,8 @@ import ( "github.com/onsi/gomega" testmatchers "github.com/solo-io/gloo/test/gomega/matchers" "github.com/solo-io/skv2/codegen/util" + + _ "embed" ) const ( @@ -45,6 +47,9 @@ var ( VSTransformationHeaderText = filepath.Join(util.MustGetThisDir(), "testdata", "transformation", "vs-transform-header-text.yaml") VSTransformationSingleReplace = filepath.Join(util.MustGetThisDir(), "testdata", "transformation", "vs-transform-single-replace.yaml") + // Valid resources + LargeConfiguration = filepath.Join(util.MustGetThisDir(), "testdata", "valid-resources", "large-configuration.yaml") + ExpectedUpstreamResp = &testmatchers.HttpResponse{ StatusCode: http.StatusOK, Body: gomega.ContainSubstring("Welcome to nginx!"), From 127d87980e418fec39cab158f1434ab91e619fae Mon Sep 17 00:00:00 2001 From: changelog-bot Date: Wed, 13 Nov 2024 12:59:03 +0000 Subject: [PATCH 09/25] Adding changelog file to new location --- changelog/v1.18.0-beta35/validate-large-configs.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/v1.18.0-beta35/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta35/validate-large-configs.yaml b/changelog/v1.18.0-beta35/validate-large-configs.yaml new file mode 100644 index 00000000000..fe46cdd4420 --- /dev/null +++ b/changelog/v1.18.0-beta35/validate-large-configs.yaml @@ -0,0 +1,9 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/solo-projects/issues/7089 + resolvesIssue: false + description: >- + Fix the validation of large configurations when using envoy validation. + Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. + This change passes the configuration as a file instead, using STDIN (/dev/fd/0) + avoiding the need to store the file on disk. \ No newline at end of file From 6044d43a9d9073f09074c82d19db44e7d79cec07 Mon Sep 17 00:00:00 2001 From: changelog-bot Date: Wed, 13 Nov 2024 12:59:04 +0000 Subject: [PATCH 10/25] Deleting changelog file from old location --- changelog/v1.18.0-beta34/validate-large-configs.yaml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 changelog/v1.18.0-beta34/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta34/validate-large-configs.yaml b/changelog/v1.18.0-beta34/validate-large-configs.yaml deleted file mode 100644 index fe46cdd4420..00000000000 --- a/changelog/v1.18.0-beta34/validate-large-configs.yaml +++ /dev/null @@ -1,9 +0,0 @@ -changelog: - - type: FIX - issueLink: https://github.com/solo-io/solo-projects/issues/7089 - resolvesIssue: false - description: >- - Fix the validation of large configurations when using envoy validation. - Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. - This change passes the configuration as a file instead, using STDIN (/dev/fd/0) - avoiding the need to store the file on disk. \ No newline at end of file From be5bb4f6e8dcc2eac100576752f934198b65972c Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Wed, 13 Nov 2024 17:01:28 -0800 Subject: [PATCH 11/25] Turned of strict mode for the full envoy tests --- projects/envoyinit/pkg/runner/run.go | 3 +- .../validation/full_envoy_validation/suite.go | 6 +- .../valid-resources/large-configuration.yaml | 584 ++++++++---------- .../manifests/full-envoy-validation-helm.yaml | 2 +- 4 files changed, 273 insertions(+), 322 deletions(-) diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index e7a671e9744..0194366ea3a 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -30,7 +30,8 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) - validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") + validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", + "-l", "critical", "--log-format", "%v") validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) if err := validateCmd.Run(); err != nil { if os.IsNotExist(err) { diff --git a/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go b/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go index f626bceb23b..ec8633ad006 100644 --- a/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go +++ b/test/kubernetes/e2e/features/validation/full_envoy_validation/suite.go @@ -76,10 +76,12 @@ func (s *testingSuite) TestRejectInvalidTransformation() { // TestLargeConfiguration checks webhook accepts large configuration when fullEnvoyValidation=true func (s *testingSuite) TestLargeConfiguration() { s.T().Cleanup(func() { - err := s.testInstallation.Actions.Kubectl().DeleteFileSafe(s.ctx, validation.LargeConfiguration, "-n", s.testInstallation.Metadata.InstallNamespace) + err := s.testInstallation.Actions.Kubectl().DeleteFileSafe(s.ctx, validation.LargeConfiguration, "-n", + s.testInstallation.Metadata.InstallNamespace) s.Assertions.NoError(err, "can delete large configuration") }) - err := s.testInstallation.Actions.Kubectl().ApplyFile(s.ctx, validation.LargeConfiguration, "-n", s.testInstallation.Metadata.InstallNamespace) + err := s.testInstallation.Actions.Kubectl().ApplyFile(s.ctx, validation.LargeConfiguration, "-n", + s.testInstallation.Metadata.InstallNamespace) s.Assert().NoError(err) } diff --git a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml index dce91ebb80c..77e89649a95 100644 --- a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml +++ b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml @@ -2,13 +2,13 @@ apiVersion: v1 kind: ServiceAccount metadata: name: httpbin - namespace: default + namespace: full-envoy-validation-test --- apiVersion: v1 kind: Service metadata: name: httpbin - namespace: default + namespace: full-envoy-validation-test labels: app: httpbin service: httpbin @@ -24,7 +24,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: httpbin - namespace: default + namespace: full-envoy-validation-test spec: replicas: 1 selector: @@ -67,11 +67,223 @@ spec: image: gcr.io/solo-public/docs/hey:0.1.4 imagePullPolicy: IfNotPresent --- +apiVersion: gloo.solo.io/v1 +kind: Upstream +metadata: + name: default-httpbin-8000 + namespace: full-envoy-validation-test +spec: + kube: + serviceName: httpbin + serviceNamespace: full-envoy-validation-test + servicePort: 8000 +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: jwt-validation-company + namespace: full-envoy-validation-test +spec: + options: +--- +apiVersion: gateway.solo.io/v1 +kind: RouteOption +metadata: + name: jwt-route-ip + namespace: full-envoy-validation-test +spec: + options: + autoHostRewrite: true + prefixRewrite: /get + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header("server") == "Google Frontend" %}{{ body() }}{% else %}{% if header(":status") == "401" %}{"error":"Invalid Token","errorCode":"INVALID_TOKEN","message":"Invalid Token","statusCode":403}{% else if header(":status") == "429" %}{"status":"fail","data":{"error":"QUOTA_EXCEEDED","path": "{{ request_header(":path") }}" }}{% else %}{{ body() }}{% endif %}{% endif %}' + headers: + :status: + text: '{% if header("server") == "Google Frontend" %}{{ header(":status") }}{% else %}{% if header(":status") == "401" %}403{% else if header(":status") == "429" %}450{% else %}{{ header(":status") }}{% endif %}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: cors-company + namespace: full-envoy-validation-test +spec: + options: + cors: + allowCredentials: true + allowHeaders: + - origin, + - x-requested-with, + - accept, + - content-type, + - authorization, + - x-something-api-key, + - x-something-device-type, + - x-something-platform, + - x-something-app-version, + - x-something-platform-version, + - x-something-default-language, + - x-something-country-code-override, + - x-something-user-token, + - x-something-install-id, + - x-something-profile-id, + - x-something-install-date, + - x-something-context-override, + - x-something-is-kid-profile, + - x-something-cosed, + - x-px-block-error, + - x-something-debug, + - x-something-token-key-id + allowMethods: + - GET + - PUT + - POST + - DELETE + - PATCH + allowOrigin: + - http://localhost:3000 + allowOriginRegex: + - https://*.company.com + exposeHeaders: + - '*' + maxAge: 3628800s +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualHostOption +metadata: + name: jwt-decode-company + namespace: full-envoy-validation-test +spec: + options: + stagedTransformations: + early: + requestTransforms: + - clearRouteCache: true + requestTransformation: + transformationTemplate: + advancedTemplates: true + extractors: + bearer: + header: authorization + regex: Bearer.(.*)\.(.*)\.(.*) + subgroup: 2 + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + body: + text: '{% if existsIn(context(), "video")%}{"video":{% set seriesMediaIdValue="default" + %}{% set nextEpisodeMediaIdValue="default" %}{% set page = at(context(), + "video") %}{ {% for key, value in page %} {% if at(loop, "is_first") + and key != "seriesMediaId" and key != "mediaId" and key != "nextEpisodeMediaId" + %}{% set first_key=key %}{% set first_value=value %}{% endif %}{% + if key == "mediaId" and substring(value, 0, 21) == "transmission:matchid:" + %}"mediaId":"video:mcp:unexpected-live-match",{% else %}{% if + key == "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% endif + %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif %}{% + endif %}{% if key == "seriesMediaId" %}{% set seriesMediaIdValue=value + %}{% endif %}{% if key == "nextEpisodeMediaId" %}{% set nextEpisodeMediaIdValue=value + %}{% endif %}{% if key != "seriesMediaId" and key != "nextEpisodeMediaId" + and key != "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% + endif %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif + %}{% endfor %}"{{first_key}}":{% if not isNumber(first_value) + %}"{% endif %}{{first_value}}{% if not isNumber(first_value) %}"{% + endif %}{% if seriesMediaIdValue != "default" and seriesMediaIdValue + != "" %},"seriesMediaId":{% if not isNumber(seriesMediaIdValue)%}"{% + endif %}{{seriesMediaIdValue}}{% if not isNumber(seriesMediaIdValue) + %}"{% endif %}{% endif %}{% if nextEpisodeMediaIdValue != "default" + and seriesMediaIdValue != "default" and seriesMediaIdValue != + "" %},"nextEpisodeMediaId":{% if not isNumber(nextEpisodeMediaIdValue)%}"{% + endif %}{{nextEpisodeMediaIdValue}}{% if not isNumber(nextEpisodeMediaIdValue) + %}"{% endif %}{% endif %} }} {% else %}{{ context() }}{% endif + %}' + extractors: + country: + header: x-something-country-code + regex: (AR|BO|CL|CO|CR|DO|EC|GT|HN|MX|NI|PA|PE|PR|PY|SV|US|UY|VE) + subgroup: 1 + profile: + header: profile-id + regex: .*?"id.{3}(\w*[-_\w*]*).* + subgroup: 1 + profile-extractor: + header: profile-extended + regex: .*?"id.{3}(\w*[-_\w*]*).* + subgroup: 1 + sub: + header: sub-claim + regex: ^(.*\|)?(.*)$ + subgroup: 2 + subscription-id: + header: x-something-subscription-info + regex: .*"subscriptionId".*?"([^"]+)".* + subgroup: 1 + subscription-id-user-token: + header: x-something-subscription-info-user-token + regex: .*"subscriptionId".*?"([^"]+)".* + subgroup: 1 + subscription-tier: + header: x-something-subscription-info-user-token + regex: .*"subscriptionTier.{3}(\w*).* + subgroup: 1 + headers: + x-something-country-blocked: + text: '{% if extraction("country") == "" %}country_not_allowed{% + endif %}' + x-something-install-id: + text: '{% if request_header("x-something-install-id") != "" %}{{ request_header("x-something-install-id") + }}{% else %}{% if header("x-something-install-id-claim") != "" %}{{ + header("x-something-install-id-claim") }}{% else %}asdfasdf{% + endif %}{% endif %}' + x-something-plan-group: + text: '{% if extraction("subscription-id") == "" %}default{% else + %}{%if extraction("subscription-id") in ["something-sv-web-prepaid-7d", + "something-gt-web-prepaid-7d", "something-gt-web-prepaid-15d", "something-gt-web-prepaid-30d", + "something-hd-web-prepaid-7d", "something-hd-web-prepaid-15d", "something-hd-web-prepaid-30d", + "something-ng-web-prepaid-7d", "something-ng-web-prepaid-15d","something-ng-web-prepaid-30d", + "something-pn-web-prepaid-7d", "something-hn-web-prepaid-standalone-7d"] + %}something-restricted{% else %}default{% endif %}{% endif%}' + x-something-plan-ids: + text: '{% if extraction("subscription-id") == "" %}{{ extraction("subscription-id-user-token") + }}{% else %}{{ extraction("subscription-id") }}{% endif %}' + x-something-profile-id: + text: '{% if request_header("x-something-profile-id") != "" %}{% set + a = false %}{% for num in range(length(header("x-something-available-profile-ids")) + / 36 ) %}{% if substring(header("x-something-available-profile-ids"), + num * 36 + num , 36) == request_header("x-something-profile-id") %}{{ + request_header("x-something-profile-id") }}{% set a = true %}{% endif + %}{% endfor %}{% if a == false %}{{ request_header("x-something-profile-id") + }}{% endif %}{% else %} {% if header("x-iss") == "identity-api.self.something.com"%} {{ + extraction("profile") }}{% else %}{% if extraction("profile-extractor") + != "" %}{{ extraction("profile-extractor") }}{% else %}{{ extraction("user-token-profile-id") + }}{% endif%}{% endif %}{% endif %}' + x-something-subscription-plan-tier: + text: '{{ extraction("subscription-tier") }}' + x-something-user-id: + text: '{{ extraction("sub") }}' + headersToRemove: + - authorization + - x-something-subscription-info + - x-something-install-id-claim + - profile-extended + - x-something-subscription-info-user-token +--- apiVersion: gateway.solo.io/v1 kind: VirtualService metadata: name: httpbin-1 - namespace: gloo-system + namespace: full-envoy-validation-test spec: virtualHost: domains: @@ -79,11 +291,11 @@ spec: optionsConfigRefs: delegateOptions: - name: cors-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-validation-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-decode-company - namespace: gloo-system + namespace: full-envoy-validation-test routes: - directResponseAction: body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' @@ -103,7 +315,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-user-token @@ -134,91 +345,83 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /ip name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /get name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /headers name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /status name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /user-agent name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /cookies name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /base64 name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - invertMatch: true @@ -247,7 +450,7 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system + namespace: full-envoy-validation-test - matchers: - headers: - name: x-something-api-key @@ -280,7 +483,7 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system + namespace: full-envoy-validation-test - matchers: - headers: - name: x-something-api-key @@ -292,7 +495,6 @@ spec: extauth: configRef: name: something - namespace: gloo-system prefixRewrite: / stagedTransformations: early: @@ -323,13 +525,12 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system + namespace: full-envoy-validation-test --- apiVersion: gateway.solo.io/v1 kind: VirtualService metadata: name: httpbin-2 - namespace: gloo-system spec: virtualHost: domains: @@ -337,11 +538,11 @@ spec: optionsConfigRefs: delegateOptions: - name: cors-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-validation-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-decode-company - namespace: gloo-system + namespace: full-envoy-validation-test routes: - directResponseAction: body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' @@ -361,7 +562,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-user-token @@ -392,91 +592,83 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /ip name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /get name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /headers name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /status name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /user-agent name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /cookies name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /base64 name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - invertMatch: true @@ -505,7 +697,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -523,13 +714,13 @@ spec: transformationTemplate: body: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}{{ body() }}{% else if header(":status") + == "Frontend" %}{{ body() }}{% else if header(":status") != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% endif %}' headers: :status: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}401{% else if header(":status") != + == "Frontend" %}401{% else if header(":status") != "401" %}{{ header(":status") }}{% else %}403{% endif %}' ignoreErrorOnParse: true inheritTransformation: true @@ -538,7 +729,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -550,7 +740,6 @@ spec: extauth: configRef: name: something - namespace: gloo-system prefixRewrite: / stagedTransformations: early: @@ -581,13 +770,11 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system --- apiVersion: gateway.solo.io/v1 kind: VirtualService metadata: name: httpbin-3 - namespace: gloo-system spec: virtualHost: domains: @@ -595,11 +782,11 @@ spec: optionsConfigRefs: delegateOptions: - name: cors-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-validation-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-decode-company - namespace: gloo-system + namespace: full-envoy-validation-test routes: - directResponseAction: body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' @@ -619,7 +806,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-user-token @@ -650,91 +836,83 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /ip name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /get name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /headers name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /status name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /user-agent name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /cookies name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /base64 name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - invertMatch: true @@ -763,7 +941,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -781,13 +958,13 @@ spec: transformationTemplate: body: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}{{ body() }}{% else if header(":status") + == "Frontend" %}{{ body() }}{% else if header(":status") != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% endif %}' headers: :status: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}401{% else if header(":status") != + == "Frontend" %}401{% else if header(":status") != "401" %}{{ header(":status") }}{% else %}403{% endif %}' ignoreErrorOnParse: true inheritTransformation: true @@ -796,7 +973,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -808,7 +984,6 @@ spec: extauth: configRef: name: something - namespace: gloo-system prefixRewrite: / stagedTransformations: early: @@ -839,25 +1014,11 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system ---- -apiVersion: gloo.solo.io/v1 -kind: Upstream -metadata: - name: default-httpbin-8000 - namespace: default -spec: - discoveryMetadata: {} - kube: - serviceName: httpbin - serviceNamespace: default - servicePort: 8000 --- apiVersion: gateway.solo.io/v1 kind: VirtualService metadata: name: httpbin-4 - namespace: gloo-system spec: virtualHost: domains: @@ -865,11 +1026,11 @@ spec: optionsConfigRefs: delegateOptions: - name: cors-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-validation-company - namespace: gloo-system + namespace: full-envoy-validation-test - name: jwt-decode-company - namespace: gloo-system + namespace: full-envoy-validation-test routes: - directResponseAction: body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' @@ -889,7 +1050,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-user-token @@ -920,91 +1080,83 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /ip name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /get name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /headers name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /status name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /user-agent name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /cookies name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - prefix: /base64 name: jwt-options-route optionsConfigRefs: delegateOptions: - name: jwt-route-ip - namespace: gloo-system + namespace: full-envoy-validation-test routeAction: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - invertMatch: true @@ -1033,7 +1185,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -1051,13 +1202,13 @@ spec: transformationTemplate: body: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}{{ body() }}{% else if header(":status") + == "Frontend" %}{{ body() }}{% else if header(":status") != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% endif %}' headers: :status: text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}401{% else if header(":status") != + == "Frontend" %}401{% else if header(":status") != "401" %}{{ header(":status") }}{% else %}403{% endif %}' ignoreErrorOnParse: true inheritTransformation: true @@ -1066,7 +1217,6 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system - matchers: - headers: - name: x-something-api-key @@ -1078,7 +1228,6 @@ spec: extauth: configRef: name: something - namespace: gloo-system prefixRewrite: / stagedTransformations: early: @@ -1109,205 +1258,4 @@ spec: single: upstream: name: default-httpbin-8000 - namespace: gloo-system ---- -apiVersion: gateway.solo.io/v1 -kind: VirtualHostOption -metadata: - name: cors-company - namespace: gloo-system -spec: - options: - cors: - allowCredentials: true - allowHeaders: - - origin, - - x-requested-with, - - accept, - - content-type, - - authorization, - - x-something-api-key, - - x-something-device-type, - - x-something-platform, - - x-something-app-version, - - x-something-platform-version, - - x-something-default-language, - - x-something-country-code-override, - - x-something-user-token, - - x-something-install-id, - - x-something-profile-id, - - x-something-install-date, - - x-something-context-override, - - x-something-is-kid-profile, - - x-something-cosed, - - x-px-block-error, - - x-something-debug, - - x-something-token-key-id - allowMethods: - - GET - - PUT - - POST - - DELETE - - PATCH - allowOrigin: - - http://localhost:3000 - allowOriginRegex: - - https://*.company.com - exposeHeaders: - - '*' - maxAge: 3628800s ---- -apiVersion: gateway.solo.io/v1 -kind: VirtualHostOption -metadata: - name: jwt-decode-company - namespace: gloo-system -spec: - options: - stagedTransformations: - early: - requestTransforms: - - clearRouteCache: true - requestTransformation: - transformationTemplate: - advancedTemplates: true - extractors: - bearer: - header: authorization - regex: Bearer.(.*)\.(.*)\.(.*) - subgroup: 2 - regular: - requestTransforms: - - clearRouteCache: true - requestTransformation: - logRequestResponseInfo: true - transformationTemplate: - advancedTemplates: true - body: - text: '{% if existsIn(context(), "video")%}{"video":{% set seriesMediaIdValue="default" - %}{% set nextEpisodeMediaIdValue="default" %}{% set page = at(context(), - "video") %}{ {% for key, value in page %} {% if at(loop, "is_first") - and key != "seriesMediaId" and key != "mediaId" and key != "nextEpisodeMediaId" - %}{% set first_key=key %}{% set first_value=value %}{% endif %}{% - if key == "mediaId" and substring(value, 0, 21) == "transmission:matchid:" - %}"mediaId":"video:mcp:unexpected-live-match",{% else %}{% if - key == "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% endif - %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif %}{% - endif %}{% if key == "seriesMediaId" %}{% set seriesMediaIdValue=value - %}{% endif %}{% if key == "nextEpisodeMediaId" %}{% set nextEpisodeMediaIdValue=value - %}{% endif %}{% if key != "seriesMediaId" and key != "nextEpisodeMediaId" - and key != "mediaId" %}"{{key}}":{% if not isNumber(value) %}"{% - endif %}{{value}}{% if not isNumber(value) %}"{% endif %},{% endif - %}{% endfor %}"{{first_key}}":{% if not isNumber(first_value) - %}"{% endif %}{{first_value}}{% if not isNumber(first_value) %}"{% - endif %}{% if seriesMediaIdValue != "default" and seriesMediaIdValue - != "" %},"seriesMediaId":{% if not isNumber(seriesMediaIdValue)%}"{% - endif %}{{seriesMediaIdValue}}{% if not isNumber(seriesMediaIdValue) - %}"{% endif %}{% endif %}{% if nextEpisodeMediaIdValue != "default" - and seriesMediaIdValue != "default" and seriesMediaIdValue != - "" %},"nextEpisodeMediaId":{% if not isNumber(nextEpisodeMediaIdValue)%}"{% - endif %}{{nextEpisodeMediaIdValue}}{% if not isNumber(nextEpisodeMediaIdValue) - %}"{% endif %}{% endif %} }} {% else %}{{ context() }}{% endif - %}' - extractors: - country: - header: x-something-country-code - regex: (AR|BO|CL|CO|CR|DO|EC|GT|HN|MX|NI|PA|PE|PR|PY|SV|US|UY|VE) - subgroup: 1 - profile: - header: profile-id - regex: .*?"id.{3}(\w*[-_\w*]*).* - subgroup: 1 - profile-extractor: - header: profile-extended - regex: .*?"id.{3}(\w*[-_\w*]*).* - subgroup: 1 - sub: - header: sub-claim - regex: ^(.*\|)?(.*)$ - subgroup: 2 - subscription-id: - header: x-something-subscription-info - regex: .*"subscriptionId".*?"([^"]+)".* - subgroup: 1 - subscription-id-user-token: - header: x-something-subscription-info-user-token - regex: .*"subscriptionId".*?"([^"]+)".* - subgroup: 1 - subscription-tier: - header: x-something-subscription-info-user-token - regex: .*"subscriptionTier.{3}(\w*).* - subgroup: 1 - headers: - x-something-country-blocked: - text: '{% if extraction("country") == "" %}country_not_allowed{% - endif %}' - x-something-install-id: - text: '{% if request_header("x-something-install-id") != "" %}{{ request_header("x-something-install-id") - }}{% else %}{% if header("x-something-install-id-claim") != "" %}{{ - header("x-something-install-id-claim") }}{% else %}asdfasdf{% - endif %}{% endif %}' - x-something-plan-group: - text: '{% if extraction("subscription-id") == "" %}default{% else - %}{%if extraction("subscription-id") in ["something-sv-web-prepaid-7d", - "something-gt-web-prepaid-7d", "something-gt-web-prepaid-15d", "something-gt-web-prepaid-30d", - "something-hd-web-prepaid-7d", "something-hd-web-prepaid-15d", "something-hd-web-prepaid-30d", - "something-ng-web-prepaid-7d", "something-ng-web-prepaid-15d","something-ng-web-prepaid-30d", - "something-pn-web-prepaid-7d", "something-hn-web-prepaid-standalone-7d"] - %}something-restricted{% else %}default{% endif %}{% endif%}' - x-something-plan-ids: - text: '{% if extraction("subscription-id") == "" %}{{ extraction("subscription-id-user-token") - }}{% else %}{{ extraction("subscription-id") }}{% endif %}' - x-something-profile-id: - text: '{% if request_header("x-something-profile-id") != "" %}{% set - a = false %}{% for num in range(length(header("x-something-available-profile-ids")) - / 36 ) %}{% if substring(header("x-something-available-profile-ids"), - num * 36 + num , 36) == request_header("x-something-profile-id") %}{{ - request_header("x-something-profile-id") }}{% set a = true %}{% endif - %}{% endfor %}{% if a == false %}{{ request_header("x-something-profile-id") - }}{% endif %}{% else %} {% if header("x-iss") == "identity-api.self.something.com"%} {{ - extraction("profile") }}{% else %}{% if extraction("profile-extractor") - != "" %}{{ extraction("profile-extractor") }}{% else %}{{ extraction("user-token-profile-id") - }}{% endif%}{% endif %}{% endif %}' - x-something-subscription-plan-tier: - text: '{{ extraction("subscription-tier") }}' - x-something-user-id: - text: '{{ extraction("sub") }}' - headersToRemove: - - authorization - - x-something-subscription-info - - x-something-install-id-claim - - profile-extended - - x-something-subscription-info-user-token ---- -apiVersion: gateway.solo.io/v1 -kind: VirtualHostOption -metadata: - name: jwt-validation-company - namespace: gloo-system -spec: - options: ---- -apiVersion: gateway.solo.io/v1 -kind: RouteOption -metadata: - name: jwt-route-ip - namespace: gloo-system -spec: - options: - autoHostRewrite: true - prefixRewrite: /get - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header("server") == "Google Frontend" %}{{ body() }}{% else %}{% if header(":status") == "401" %}{"error":"Invalid Token","errorCode":"INVALID_TOKEN","message":"Invalid Token","statusCode":403}{% else if header(":status") == "429" %}{"status":"fail","data":{"error":"QUOTA_EXCEEDED","path": "{{ request_header(":path") }}" }}{% else %}{{ body() }}{% endif %}{% endif %}' - headers: - :status: - text: '{% if header("server") == "Google Frontend" %}{{ header(":status") }}{% else %}{% if header(":status") == "401" %}403{% else if header(":status") == "429" %}450{% else %}{{ header(":status") }}{% endif %}{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s + diff --git a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml index 2c13d97feb5..ba9010a1df2 100644 --- a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml +++ b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml @@ -1,7 +1,7 @@ gateway: validation: failurePolicy: Fail # For "strict" validation mode, fail the validation if webhook server is not available - allowWarnings: false # For "strict" validation mode, webhook will also reject warnings + allowWarnings: true # These tests to not need to fail on warnings # transformation validation is disabled because full envoy validation is enabled. disableTransformationValidation: true fullEnvoyValidation: true From 22fabd18da8240dabdb8cff94349842cd6fe3c84 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Wed, 13 Nov 2024 17:59:09 -0800 Subject: [PATCH 12/25] Added make target to help keep versions uniform --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7f0d6fc2940..9ec58a01bcf 100644 --- a/Makefile +++ b/Makefile @@ -287,10 +287,9 @@ run-hashicorp-e2e-tests: GINKGO_FLAGS += --label-filter="end-to-end && !performa run-hashicorp-e2e-tests: test .PHONY: run-kube-e2e-tests -run-kube-e2e-tests: TEST_PKG = ./test/kube2e/$(KUBE2E_TESTS) ## Run the Kubernetes E2E Tests in the {KUBE2E_TESTS} package +run-kube-e2e-tests: TEST_PKG = ./test/kube2e/$(KUBE2E_TESTS) ## Run the legacy Kubernetes E2E Tests in the {KUBE2E_TESTS} package run-kube-e2e-tests: test - #---------------------------------------------------------------------------------- # Go Tests #---------------------------------------------------------------------------------- @@ -1096,6 +1095,9 @@ endif # distroless images CLUSTER_NAME ?= kind INSTALL_NAMESPACE ?= gloo-system +kind-setup: + VERSION=${VERSION} CLUSTER_NAME=${CLUSTER_NAME} ./ci/kind/setup-kind.sh + kind-load-%-distroless: kind load docker-image $(IMAGE_REGISTRY)/$*:$(VERSION)-distroless --name $(CLUSTER_NAME) From 34a71c1e6aade299b6e1064e6326e2de7a70b5a5 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Wed, 13 Nov 2024 17:59:29 -0800 Subject: [PATCH 13/25] Removed an extra VS from large config test --- .../valid-resources/large-configuration.yaml | 489 ------------------ 1 file changed, 489 deletions(-) diff --git a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml index 77e89649a95..1709fc79118 100644 --- a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml +++ b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml @@ -770,492 +770,3 @@ spec: single: upstream: name: default-httpbin-8000 ---- -apiVersion: gateway.solo.io/v1 -kind: VirtualService -metadata: - name: httpbin-3 -spec: - virtualHost: - domains: - - httpbin-3.example.io - optionsConfigRefs: - delegateOptions: - - name: cors-company - namespace: full-envoy-validation-test - - name: jwt-validation-company - namespace: full-envoy-validation-test - - name: jwt-decode-company - namespace: full-envoy-validation-test - routes: - - directResponseAction: - body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' - status: 451 - matchers: - - headers: - - name: x-something-country-blocked - value: country_not_allowed - prefix: / - - matchers: - - exact: /gql/v2/healthcheck - options: - autoHostRewrite: true - prefixRewrite: /healthcheck - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-user-token - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}{{ body() }}{% else if header(":status") - != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% - endif %}' - headers: - :status: - text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}401{% else if header(":status") != - "401" %}{{ header(":status") }}{% else %}403{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /ip - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /get - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /headers - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /status - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /user-agent - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /cookies - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /base64 - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - invertMatch: true - name: x-something-api-key - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% - else %}{{ body() }}{% endif%}' - headers: - :status: - text: '{% if header(":status") == "401" %}403{% else %}{{ - header(":status") }}{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-api-key - regex: true - value: ^$ - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" and header("server") - == "Frontend" %}{{ body() }}{% else if header(":status") - != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% - endif %}' - headers: - :status: - text: '{% if header(":status") == "401" and header("server") - == "Frontend" %}401{% else if header(":status") != - "401" %}{{ header(":status") }}{% else %}403{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-api-key - regex: true - value: .+ - prefix: /gql/v2 - options: - autoHostRewrite: true - extauth: - configRef: - name: something - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - transformationTemplate: - body: - text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% - else %}{{ context() }}{% endif %}' - headers: - :status: - text: '{% if header(":status") == "401" %}403{% else %}{{ - header(":status") }}{% endif %}' - regular: - requestTransforms: - - clearRouteCache: true - requestTransformation: - logRequestResponseInfo: true - transformationTemplate: - advancedTemplates: true - headers: - x-something-profile-id: - text: web-app-ssr - x-something-user-id: - text: web-app-ssr - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 ---- -apiVersion: gateway.solo.io/v1 -kind: VirtualService -metadata: - name: httpbin-4 -spec: - virtualHost: - domains: - - httpbin-4.example.io - optionsConfigRefs: - delegateOptions: - - name: cors-company - namespace: full-envoy-validation-test - - name: jwt-validation-company - namespace: full-envoy-validation-test - - name: jwt-decode-company - namespace: full-envoy-validation-test - routes: - - directResponseAction: - body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' - status: 451 - matchers: - - headers: - - name: x-something-country-blocked - value: country_not_allowed - prefix: / - - matchers: - - exact: /gql/v2/healthcheck - options: - autoHostRewrite: true - prefixRewrite: /healthcheck - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-user-token - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}{{ body() }}{% else if header(":status") - != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% - endif %}' - headers: - :status: - text: '{% if header(":status") == "401" and header("server") - == "Google Frontend" %}401{% else if header(":status") != - "401" %}{{ header(":status") }}{% else %}403{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /ip - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /get - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /headers - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /status - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /user-agent - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /cookies - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - prefix: /base64 - name: jwt-options-route - optionsConfigRefs: - delegateOptions: - - name: jwt-route-ip - namespace: full-envoy-validation-test - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - invertMatch: true - name: x-something-api-key - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% - else %}{{ body() }}{% endif%}' - headers: - :status: - text: '{% if header(":status") == "401" %}403{% else %}{{ - header(":status") }}{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-api-key - regex: true - value: ^$ - prefix: /gql/v2 - options: - autoHostRewrite: true - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - logRequestResponseInfo: true - transformationTemplate: - body: - text: '{% if header(":status") == "401" and header("server") - == "Frontend" %}{{ body() }}{% else if header(":status") - != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% - endif %}' - headers: - :status: - text: '{% if header(":status") == "401" and header("server") - == "Frontend" %}401{% else if header(":status") != - "401" %}{{ header(":status") }}{% else %}403{% endif %}' - ignoreErrorOnParse: true - inheritTransformation: true - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - - matchers: - - headers: - - name: x-something-api-key - regex: true - value: .+ - prefix: /gql/v2 - options: - autoHostRewrite: true - extauth: - configRef: - name: something - prefixRewrite: / - stagedTransformations: - early: - responseTransforms: - - responseTransformation: - transformationTemplate: - body: - text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% - else %}{{ context() }}{% endif %}' - headers: - :status: - text: '{% if header(":status") == "401" %}403{% else %}{{ - header(":status") }}{% endif %}' - regular: - requestTransforms: - - clearRouteCache: true - requestTransformation: - logRequestResponseInfo: true - transformationTemplate: - advancedTemplates: true - headers: - x-something-profile-id: - text: web-app-ssr - x-something-user-id: - text: web-app-ssr - timeout: 31s - routeAction: - single: - upstream: - name: default-httpbin-8000 - From 3fe5d335f2685b9e499425db8be8ac210b506247 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 08:03:37 -0800 Subject: [PATCH 14/25] Removed a superceeded test and embed line --- test/kube2e/gloo/large_configuration_test.go | 43 ------------------- .../e2e/features/validation/types.go | 2 - 2 files changed, 45 deletions(-) delete mode 100644 test/kube2e/gloo/large_configuration_test.go diff --git a/test/kube2e/gloo/large_configuration_test.go b/test/kube2e/gloo/large_configuration_test.go deleted file mode 100644 index 80b72dbd3f2..00000000000 --- a/test/kube2e/gloo/large_configuration_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package gloo_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/solo-io/gloo/projects/gloo/pkg/api/v1/gloosnapshot" - - "github.com/solo-io/solo-kit/pkg/api/v1/clients" -) - -var _ = Describe("Large configuration", func() { - var ( - glooResources *gloosnapshot.ApiSnapshot - ) - - BeforeEach(func() { - glooResources = &gloosnapshot.ApiSnapshot{} - }) - - JustBeforeEach(func() { - err := snapshotWriter.WriteSnapshot(glooResources, clients.WriteOpts{ - Ctx: ctx, - OverwriteExisting: false, - }) - Expect(err).NotTo(HaveOccurred()) - }) - - JustAfterEach(func() { - err := snapshotWriter.DeleteSnapshot(glooResources, clients.DeleteOpts{ - Ctx: ctx, - IgnoreNotExist: true, - }) - Expect(err).NotTo(HaveOccurred()) - }) - - // We have a customer that was experiencing issue with full validation of a large configuration. - // They were seeing an `argument list too long` error. - // This test is to ensure that we can create a large configuration that is representative of their use case. - It("should be able to create a large configuration", func() { - err := testHelper.ApplyFile(ctx, testHelper.RootDir+"/test/kube2e/gloo/artifacts/large-configuration.yaml") - Expect(err).NotTo(HaveOccurred()) - }) -}) diff --git a/test/kubernetes/e2e/features/validation/types.go b/test/kubernetes/e2e/features/validation/types.go index e2df5799e3f..f96cce41ea1 100644 --- a/test/kubernetes/e2e/features/validation/types.go +++ b/test/kubernetes/e2e/features/validation/types.go @@ -7,8 +7,6 @@ import ( "github.com/onsi/gomega" testmatchers "github.com/solo-io/gloo/test/gomega/matchers" "github.com/solo-io/skv2/codegen/util" - - _ "embed" ) const ( From 04463801ebd3b3296d35616b1960aba1b0537013 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 08:05:57 -0800 Subject: [PATCH 15/25] Moved changelog --- changelog/v1.18.0-beta35/validate-large-configs.yaml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 changelog/v1.18.0-beta35/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta35/validate-large-configs.yaml b/changelog/v1.18.0-beta35/validate-large-configs.yaml deleted file mode 100644 index fe46cdd4420..00000000000 --- a/changelog/v1.18.0-beta35/validate-large-configs.yaml +++ /dev/null @@ -1,9 +0,0 @@ -changelog: - - type: FIX - issueLink: https://github.com/solo-io/solo-projects/issues/7089 - resolvesIssue: false - description: >- - Fix the validation of large configurations when using envoy validation. - Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. - This change passes the configuration as a file instead, using STDIN (/dev/fd/0) - avoiding the need to store the file on disk. \ No newline at end of file From eba6c0baac83914d6f4a07931c1e6f53d9f8a653 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 08:06:40 -0800 Subject: [PATCH 16/25] Readded changelog --- changelog/v1.18.0-beta34/validate-large-configs.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/v1.18.0-beta34/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta34/validate-large-configs.yaml b/changelog/v1.18.0-beta34/validate-large-configs.yaml new file mode 100644 index 00000000000..fe46cdd4420 --- /dev/null +++ b/changelog/v1.18.0-beta34/validate-large-configs.yaml @@ -0,0 +1,9 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/solo-projects/issues/7089 + resolvesIssue: false + description: >- + Fix the validation of large configurations when using envoy validation. + Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. + This change passes the configuration as a file instead, using STDIN (/dev/fd/0) + avoiding the need to store the file on disk. \ No newline at end of file From 69b546bfc66310544f0abe4615264953f23c70fb Mon Sep 17 00:00:00 2001 From: changelog-bot Date: Thu, 14 Nov 2024 16:30:37 +0000 Subject: [PATCH 17/25] Adding changelog file to new location --- changelog/v1.18.0-beta35/validate-large-configs.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 changelog/v1.18.0-beta35/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta35/validate-large-configs.yaml b/changelog/v1.18.0-beta35/validate-large-configs.yaml new file mode 100644 index 00000000000..fe46cdd4420 --- /dev/null +++ b/changelog/v1.18.0-beta35/validate-large-configs.yaml @@ -0,0 +1,9 @@ +changelog: + - type: FIX + issueLink: https://github.com/solo-io/solo-projects/issues/7089 + resolvesIssue: false + description: >- + Fix the validation of large configurations when using envoy validation. + Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. + This change passes the configuration as a file instead, using STDIN (/dev/fd/0) + avoiding the need to store the file on disk. \ No newline at end of file From 19c5c4bd1571f039b168b91f363af5f9c468a5f7 Mon Sep 17 00:00:00 2001 From: changelog-bot Date: Thu, 14 Nov 2024 16:30:37 +0000 Subject: [PATCH 18/25] Deleting changelog file from old location --- changelog/v1.18.0-beta34/validate-large-configs.yaml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 changelog/v1.18.0-beta34/validate-large-configs.yaml diff --git a/changelog/v1.18.0-beta34/validate-large-configs.yaml b/changelog/v1.18.0-beta34/validate-large-configs.yaml deleted file mode 100644 index fe46cdd4420..00000000000 --- a/changelog/v1.18.0-beta34/validate-large-configs.yaml +++ /dev/null @@ -1,9 +0,0 @@ -changelog: - - type: FIX - issueLink: https://github.com/solo-io/solo-projects/issues/7089 - resolvesIssue: false - description: >- - Fix the validation of large configurations when using envoy validation. - Previously if the configuration grew too large translation would be blocked unless Transformation Validation was disabled. - This change passes the configuration as a file instead, using STDIN (/dev/fd/0) - avoiding the need to store the file on disk. \ No newline at end of file From 45ea63be174e1a4f0e30c2286fd7499316654a1d Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 10:19:29 -0800 Subject: [PATCH 19/25] Increased validating webhook timeout in tests and added note to full envoy validation option --- .../solo-io/gloo/projects/gloo/api/v1/settings.proto.sk.md | 2 +- projects/gloo/api/v1/settings.proto | 4 ++++ projects/gloo/pkg/api/v1/settings.pb.go | 4 ++++ .../features/validation/validation_reject_invalid/suite.go | 4 ++-- .../e2e/tests/manifests/full-envoy-validation-helm.yaml | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/content/reference/api/github.com/solo-io/gloo/projects/gloo/api/v1/settings.proto.sk.md b/docs/content/reference/api/github.com/solo-io/gloo/projects/gloo/api/v1/settings.proto.sk.md index cc582853163..02c1dfa4b76 100644 --- a/docs/content/reference/api/github.com/solo-io/gloo/projects/gloo/api/v1/settings.proto.sk.md +++ b/docs/content/reference/api/github.com/solo-io/gloo/projects/gloo/api/v1/settings.proto.sk.md @@ -948,7 +948,7 @@ options for configuring admission control / validation | `validationServerGrpcMaxSizeBytes` | [.google.protobuf.Int32Value](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/int-32-value) | By default, gRPC validation messages between gateway and gloo pods have a max message size of 100 MB. Setting this value sets the gRPC max message size in bytes for the gloo validation server. This should only be changed if necessary. If not included, the gRPC max message size will be the default of 100 MB. | | `serverEnabled` | [.google.protobuf.BoolValue](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/bool-value) | By providing the validation field (parent of this object) the user is implicitly opting into validation. This field allows the user to opt out of the validation server, while still configuring pre-existing fields such as `warn_route_short_circuiting` and `disable_transformation_validation`. If not included, the validation server will be enabled. | | `warnMissingTlsSecret` | [.google.protobuf.BoolValue](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/bool-value) | Allows configuring validation to report a missing TLS secret referenced by a SslConfig or UpstreamSslConfig as a warning instead of an error. This will allow for eventually consistent workloads, but will also permit the accidental deletion of secrets being referenced, which would cause disruption in traffic. | -| `fullEnvoyValidation` | [.google.protobuf.BoolValue](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/bool-value) | Configures the Gloo translation loop to send the final product of translation through Envoy validation mode. This has an negative impact on the total translation throughput, but it helps ensure the configuration will not be nacked when served to Envoy. This feature is disabled by default and is not recommended for production deployments unless the performance implications are well understood and acceptable. | +| `fullEnvoyValidation` | [.google.protobuf.BoolValue](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/bool-value) | Configures the Gloo translation loop to send the final product of translation through Envoy validation mode. This has an negative impact on the total translation throughput, but it helps ensure the configuration will not be nacked when served to Envoy. This feature is disabled by default and is not recommended for production deployments unless the performance implications are well understood and acceptable. Large configurations can take more than 10 seconds to validate, causing the validating webhook to timeout. When enabling this feature, consider increasing the timeout for the validating webhook (`.Values.gateway.validation.webhook.timeoutSeconds`). | diff --git a/projects/gloo/api/v1/settings.proto b/projects/gloo/api/v1/settings.proto index 31157ffade1..6f80712509d 100644 --- a/projects/gloo/api/v1/settings.proto +++ b/projects/gloo/api/v1/settings.proto @@ -918,6 +918,10 @@ message GatewayOptions { // // This feature is disabled by default and is not recommended for production deployments unless // the performance implications are well understood and acceptable. + // + // Large configurations can take more than 10 seconds to validate, causing the validating webhook to timeout. + // When enabling this feature, consider increasing the timeout for the validating webhook + // (`.Values.gateway.validation.webhook.timeoutSeconds`). google.protobuf.BoolValue full_envoy_validation = 14; } diff --git a/projects/gloo/pkg/api/v1/settings.pb.go b/projects/gloo/pkg/api/v1/settings.pb.go index 6de601552f2..fe13e544fff 100644 --- a/projects/gloo/pkg/api/v1/settings.pb.go +++ b/projects/gloo/pkg/api/v1/settings.pb.go @@ -3435,6 +3435,10 @@ type GatewayOptions_ValidationOptions struct { // // This feature is disabled by default and is not recommended for production deployments unless // the performance implications are well understood and acceptable. + // + // Large configurations can take more than 10 seconds to validate, causing the validating webhook to timeout. + // When enabling this feature, consider increasing the timeout for the validating webhook + // (`.Values.gateway.validation.webhook.timeoutSeconds`). FullEnvoyValidation *wrapperspb.BoolValue `protobuf:"bytes,14,opt,name=full_envoy_validation,json=fullEnvoyValidation,proto3" json:"full_envoy_validation,omitempty"` } diff --git a/test/kubernetes/e2e/features/validation/validation_reject_invalid/suite.go b/test/kubernetes/e2e/features/validation/validation_reject_invalid/suite.go index 510bcee937e..275d042bca8 100644 --- a/test/kubernetes/e2e/features/validation/validation_reject_invalid/suite.go +++ b/test/kubernetes/e2e/features/validation/validation_reject_invalid/suite.go @@ -221,13 +221,13 @@ func (s *testingSuite) TestRejectTransformation() { // this should be rejected output, err = s.testInstallation.Actions.Kubectl().ApplyFileWithOutput(s.ctx, validation.VSTransformationExtractors, "-n", s.testInstallation.Metadata.InstallNamespace) s.Assert().Error(err) - s.Assert().Contains(output, "envoy validation mode output: error initializing configuration '': Failed to parse response template: group 1 requested for regex with only 0 sub groups") + s.Assert().Contains(output, "Failed to parse response template: group 1 requested for regex with only 0 sub groups") // Single replace mode -- rejects invalid subgroup in transformation // note that the regex has no subgroups, but we are trying to extract the first subgroup // this should be rejected output, err = s.testInstallation.Actions.Kubectl().ApplyFileWithOutput(s.ctx, validation.VSTransformationSingleReplace, "-n", s.testInstallation.Metadata.InstallNamespace) s.Assert().Error(err) - s.Assert().Contains(output, "envoy validation mode output: error initializing configuration '': Failed to parse response template: group 1 requested for regex with only 0 sub groups") + s.Assert().Contains(output, "Failed to parse response template: group 1 requested for regex with only 0 sub groups") } diff --git a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml index ba9010a1df2..7a0afeef60c 100644 --- a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml +++ b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml @@ -4,4 +4,6 @@ gateway: allowWarnings: true # These tests to not need to fail on warnings # transformation validation is disabled because full envoy validation is enabled. disableTransformationValidation: true + webhook: + timeoutSeconds: 30 # We are seeing Envoy take 10s of seconds to validate some of the larger configurations fullEnvoyValidation: true From ebee9c3e4cf0d133ee5ee14c3156c56fc29dc04d Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 15:59:30 -0800 Subject: [PATCH 20/25] Removed logging line that was writing whole request body for validating webhook calls --- .../pkg/services/k8sadmission/validating_admission_webhook.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go b/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go index 7b19141dc30..97702a250e8 100644 --- a/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go +++ b/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go @@ -8,7 +8,6 @@ import ( "io" "log" "net/http" - "net/http/httputil" "slices" "time" @@ -228,9 +227,6 @@ func (wh *gatewayValidationWebhook) ServeHTTP(w http.ResponseWriter, r *http.Req logger.Debug("received validation request on webhook") - b, _ := httputil.DumpRequest(r, true) - logger.Debugf("validation request dump:\n %s", string(b)) - // Verify the content type is accurate contentType := r.Header.Get("Content-Type") if contentType != ApplicationJson && contentType != ApplicationYaml { From c22c171928e9ab6378d93b8d0ce51fc398b46955 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Thu, 14 Nov 2024 15:59:57 -0800 Subject: [PATCH 21/25] Adding another VS to the test data --- .../valid-resources/large-configuration.yaml | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml index 1709fc79118..c35044993e5 100644 --- a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml +++ b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml @@ -770,3 +770,247 @@ spec: single: upstream: name: default-httpbin-8000 +--- +apiVersion: gateway.solo.io/v1 +kind: VirtualService +metadata: + name: httpbin-3 +spec: + virtualHost: + domains: + - httpbin-3.example.io + optionsConfigRefs: + delegateOptions: + - name: cors-company + namespace: full-envoy-validation-test + - name: jwt-validation-company + namespace: full-envoy-validation-test + - name: jwt-decode-company + namespace: full-envoy-validation-test + routes: + - directResponseAction: + body: '{"status":"fail","data":{"error":"COUNTRY_BLOCKED"}' + status: 451 + matchers: + - headers: + - name: x-something-country-blocked + value: country_not_allowed + prefix: / + - matchers: + - exact: /gql/v2/healthcheck + options: + autoHostRewrite: true + prefixRewrite: /healthcheck + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - headers: + - name: x-something-user-token + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Google Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /ip + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /get + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /headers + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /status + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /user-agent + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /cookies + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - prefix: /base64 + name: jwt-options-route + optionsConfigRefs: + delegateOptions: + - name: jwt-route-ip + namespace: full-envoy-validation-test + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - headers: + - invertMatch: true + name: x-something-api-key + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_TOKEN"}}{% + else %}{{ body() }}{% endif%}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: ^$ + prefix: /gql/v2 + options: + autoHostRewrite: true + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + logRequestResponseInfo: true + transformationTemplate: + body: + text: '{% if header(":status") == "401" and header("server") + == "Frontend" %}{{ body() }}{% else if header(":status") + != "401" %}{{ body() }}{% else %}{"status":"fail","data":{"error":"INVALID_TOKEN"}{% + endif %}' + headers: + :status: + text: '{% if header(":status") == "401" and header("server") + == "Frontend" %}401{% else if header(":status") != + "401" %}{{ header(":status") }}{% else %}403{% endif %}' + ignoreErrorOnParse: true + inheritTransformation: true + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 + - matchers: + - headers: + - name: x-something-api-key + regex: true + value: .+ + prefix: /gql/v2 + options: + autoHostRewrite: true + extauth: + configRef: + name: something + prefixRewrite: / + stagedTransformations: + early: + responseTransforms: + - responseTransformation: + transformationTemplate: + body: + text: '{% if header(":status") == "401" %}{"status":"fail","data":{"error":"INVALID_API_KEY"}{% + else %}{{ context() }}{% endif %}' + headers: + :status: + text: '{% if header(":status") == "401" %}403{% else %}{{ + header(":status") }}{% endif %}' + regular: + requestTransforms: + - clearRouteCache: true + requestTransformation: + logRequestResponseInfo: true + transformationTemplate: + advancedTemplates: true + headers: + x-something-profile-id: + text: web-app-ssr + x-something-user-id: + text: web-app-ssr + timeout: 31s + routeAction: + single: + upstream: + name: default-httpbin-8000 \ No newline at end of file From a82c97c2c24c32c7d49e9c8cbcdd20230cc3494b Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Fri, 15 Nov 2024 10:30:41 -0800 Subject: [PATCH 22/25] Partial work --- projects/envoyinit/pkg/runner/run.go | 8 ++++- .../valid-resources/large-configuration.yaml | 32 +++++++++---------- test/kubernetes/e2e/test.go | 4 +++ .../manifests/full-envoy-validation-helm.yaml | 3 ++ .../testutils/assertions/deployments.go | 5 ++- test/testutils/env.go | 9 ++++++ 6 files changed, 41 insertions(+), 20 deletions(-) diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index 0194366ea3a..f69103fd743 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -6,6 +6,7 @@ import ( "log" "os" "syscall" + "time" "github.com/rotisserie/eris" "github.com/solo-io/gloo/pkg/utils/cmdutils" @@ -33,7 +34,12 @@ func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig stri validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) - if err := validateCmd.Run(); err != nil { + + start := time.Now() + err := validateCmd.Run() + logger.Infof("full envoy validation of %d size completed in %s", len(bootstrapConfig), time.Since(start)) + + if err != nil { if os.IsNotExist(err) { // log a warning and return nil; will allow users to continue to run Gloo locally without // relying on the Gloo container with Envoy already published to the expected directory diff --git a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml index c35044993e5..e10fee89e95 100644 --- a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml +++ b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml @@ -2,23 +2,8 @@ apiVersion: v1 kind: ServiceAccount metadata: name: httpbin - namespace: full-envoy-validation-test + namespace: full-envoy-validation-test --- -apiVersion: v1 -kind: Service -metadata: - name: httpbin - namespace: full-envoy-validation-test - labels: - app: httpbin - service: httpbin -spec: - ports: - - name: http - port: 8000 - targetPort: 8080 - selector: - app: httpbin --- apiVersion: apps/v1 kind: Deployment @@ -67,6 +52,21 @@ spec: image: gcr.io/solo-public/docs/hey:0.1.4 imagePullPolicy: IfNotPresent --- +apiVersion: v1 +kind: Service +metadata: + name: httpbin + namespace: full-envoy-validation-test + labels: + app: httpbin + service: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 8080 + selector: + app: httpbin apiVersion: gloo.solo.io/v1 kind: Upstream metadata: diff --git a/test/kubernetes/e2e/test.go b/test/kubernetes/e2e/test.go index 7690d5cb474..d3aad683021 100644 --- a/test/kubernetes/e2e/test.go +++ b/test/kubernetes/e2e/test.go @@ -217,6 +217,10 @@ func (i *TestInstallation) UninstallGlooGatewayWithTestHelper(ctx context.Contex } func (i *TestInstallation) UninstallGlooGateway(ctx context.Context, uninstallFn func(ctx context.Context) error) { + if testutils.ShouldSkipUninstall() { + return + } + if testutils.ShouldSkipInstall() { return } diff --git a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml index 7a0afeef60c..c4644f094bc 100644 --- a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml +++ b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml @@ -7,3 +7,6 @@ gateway: webhook: timeoutSeconds: 30 # We are seeing Envoy take 10s of seconds to validate some of the larger configurations fullEnvoyValidation: true + +gloo: + logLevel: info diff --git a/test/kubernetes/testutils/assertions/deployments.go b/test/kubernetes/testutils/assertions/deployments.go index ea36c94c561..1012c6952e9 100644 --- a/test/kubernetes/testutils/assertions/deployments.go +++ b/test/kubernetes/testutils/assertions/deployments.go @@ -11,7 +11,6 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/types" - "go.uber.org/zap/zapcore" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -42,7 +41,7 @@ func (p *Provider) EventuallyGlooReachesConsistentState(installNamespace string) // Gloo components are configured to log to the Info level by default but for these e2e tests we explicitly enable debug logging // This is done so we can triage failures after the fact and matches the process users will take to troubleshoot - logLevelAssertion := assertions.LogLevelAssertion(zapcore.DebugLevel) + //logLevelAssertion := assertions.LogLevelAssertion(zapcore.DebugLevel) // The emitter at some point should stabilize and not continue to increase the number of snapshots produced // We choose 4 here as a bit of a magic number, but we feel comfortable that if 4 consecutive polls of the metrics @@ -51,7 +50,7 @@ func (p *Provider) EventuallyGlooReachesConsistentState(installNamespace string) emitterMetricAssertion, _ := assertions.IntStatisticReachesConsistentValueAssertion("api_gloosnapshot_gloo_solo_io_emitter_snap_out", identicalResultInARow) assertions.EventuallyStatisticsMatchAssertions(glooStatsForwardConfig, - logLevelAssertion, + //logLevelAssertion, emitterMetricAssertion, ) } diff --git a/test/testutils/env.go b/test/testutils/env.go index 0e59f20d7f8..f83165fc6f2 100644 --- a/test/testutils/env.go +++ b/test/testutils/env.go @@ -13,6 +13,10 @@ const ( // installation from a previous run SkipInstall = "SKIP_INSTALL" + // SkipUninstall can be used when running Kube suites consecutively, and you don't want to uninstall Gloo + // after the test suite completes + SkipUninstall = "SKIP_UNINSTALL" + // InstallNamespace is the namespace in which Gloo is installed InstallNamespace = "INSTALL_NAMESPACE" @@ -98,6 +102,11 @@ func ShouldSkipInstall() bool { return IsEnvTruthy(SkipInstall) } +// ShouldSkipUninstall returns true if the uninstall of Gloo should be skipped after a test +func ShouldSkipUninstall() bool { + return IsEnvTruthy(SkipUninstall) +} + // ShouldSkipIstioInstall returns true if any assets that need to be created before a test (for example Gloo being installed) // should be skipped. This is typically used in tandem with ShouldTearDown when running consecutive tests and skipping // both the tear down and install of Gloo Edge. From ec7e518789ac67fe2bfebc9628839299bcb36ee3 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Mon, 18 Nov 2024 09:04:41 -0800 Subject: [PATCH 23/25] Partial chnages --- projects/envoyinit/pkg/runner/run.go | 2 ++ .../testdata/valid-resources/large-configuration.yaml | 10 ---------- test/kubernetes/e2e/test.go | 6 +----- .../tests/manifests/full-envoy-validation-helm.yaml | 3 --- test/testutils/env.go | 9 --------- 5 files changed, 3 insertions(+), 27 deletions(-) diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index f69103fd743..d1e42e0b98c 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -31,6 +31,8 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) + logger.Infof("starting full envoy validation with size %d", len(bootstrapConfig)) + validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") validateCmd = validateCmd.WithStdin(bytes.NewBufferString(bootstrapConfig)) diff --git a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml index e10fee89e95..4a62c86c730 100644 --- a/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml +++ b/test/kubernetes/e2e/features/validation/testdata/valid-resources/large-configuration.yaml @@ -4,7 +4,6 @@ metadata: name: httpbin namespace: full-envoy-validation-test --- ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -492,9 +491,6 @@ spec: prefix: /gql/v2 options: autoHostRewrite: true - extauth: - configRef: - name: something prefixRewrite: / stagedTransformations: early: @@ -737,9 +733,6 @@ spec: prefix: /gql/v2 options: autoHostRewrite: true - extauth: - configRef: - name: something prefixRewrite: / stagedTransformations: early: @@ -981,9 +974,6 @@ spec: prefix: /gql/v2 options: autoHostRewrite: true - extauth: - configRef: - name: something prefixRewrite: / stagedTransformations: early: diff --git a/test/kubernetes/e2e/test.go b/test/kubernetes/e2e/test.go index d3aad683021..31192c5409a 100644 --- a/test/kubernetes/e2e/test.go +++ b/test/kubernetes/e2e/test.go @@ -217,11 +217,7 @@ func (i *TestInstallation) UninstallGlooGatewayWithTestHelper(ctx context.Contex } func (i *TestInstallation) UninstallGlooGateway(ctx context.Context, uninstallFn func(ctx context.Context) error) { - if testutils.ShouldSkipUninstall() { - return - } - - if testutils.ShouldSkipInstall() { + if !testutils.ShouldTearDown() { return } err := uninstallFn(ctx) diff --git a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml index c4644f094bc..7a0afeef60c 100644 --- a/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml +++ b/test/kubernetes/e2e/tests/manifests/full-envoy-validation-helm.yaml @@ -7,6 +7,3 @@ gateway: webhook: timeoutSeconds: 30 # We are seeing Envoy take 10s of seconds to validate some of the larger configurations fullEnvoyValidation: true - -gloo: - logLevel: info diff --git a/test/testutils/env.go b/test/testutils/env.go index f83165fc6f2..0e59f20d7f8 100644 --- a/test/testutils/env.go +++ b/test/testutils/env.go @@ -13,10 +13,6 @@ const ( // installation from a previous run SkipInstall = "SKIP_INSTALL" - // SkipUninstall can be used when running Kube suites consecutively, and you don't want to uninstall Gloo - // after the test suite completes - SkipUninstall = "SKIP_UNINSTALL" - // InstallNamespace is the namespace in which Gloo is installed InstallNamespace = "INSTALL_NAMESPACE" @@ -102,11 +98,6 @@ func ShouldSkipInstall() bool { return IsEnvTruthy(SkipInstall) } -// ShouldSkipUninstall returns true if the uninstall of Gloo should be skipped after a test -func ShouldSkipUninstall() bool { - return IsEnvTruthy(SkipUninstall) -} - // ShouldSkipIstioInstall returns true if any assets that need to be created before a test (for example Gloo being installed) // should be skipped. This is typically used in tandem with ShouldTearDown when running consecutive tests and skipping // both the tear down and install of Gloo Edge. From 156445d622b47cc307ee54fc0a0aeacb21be6159 Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Mon, 18 Nov 2024 09:26:39 -0800 Subject: [PATCH 24/25] Undoing a change --- test/kubernetes/e2e/test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kubernetes/e2e/test.go b/test/kubernetes/e2e/test.go index 31192c5409a..7690d5cb474 100644 --- a/test/kubernetes/e2e/test.go +++ b/test/kubernetes/e2e/test.go @@ -217,7 +217,7 @@ func (i *TestInstallation) UninstallGlooGatewayWithTestHelper(ctx context.Contex } func (i *TestInstallation) UninstallGlooGateway(ctx context.Context, uninstallFn func(ctx context.Context) error) { - if !testutils.ShouldTearDown() { + if testutils.ShouldSkipInstall() { return } err := uninstallFn(ctx) From f66364459c8dc82977ed6e94bdecdb928f6f3e6f Mon Sep 17 00:00:00 2001 From: Ryan Old Date: Mon, 18 Nov 2024 11:16:03 -0800 Subject: [PATCH 25/25] Undoing some changes --- projects/envoyinit/pkg/runner/run.go | 4 ++-- .../services/k8sadmission/validating_admission_webhook.go | 4 ++++ test/kubernetes/testutils/assertions/deployments.go | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/projects/envoyinit/pkg/runner/run.go b/projects/envoyinit/pkg/runner/run.go index d1e42e0b98c..7ea336c528b 100644 --- a/projects/envoyinit/pkg/runner/run.go +++ b/projects/envoyinit/pkg/runner/run.go @@ -31,7 +31,7 @@ const ( func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig string) error { logger := contextutils.LoggerFrom(ctx) - logger.Infof("starting full envoy validation with size %d", len(bootstrapConfig)) + logger.Debugf("starting full envoy validation with size %d", len(bootstrapConfig)) validateCmd := cmdutils.Command(ctx, envoyExecutable, "--mode", "validate", "--config-path", "/dev/fd/0", "-l", "critical", "--log-format", "%v") @@ -39,7 +39,7 @@ func RunEnvoyValidate(ctx context.Context, envoyExecutable, bootstrapConfig stri start := time.Now() err := validateCmd.Run() - logger.Infof("full envoy validation of %d size completed in %s", len(bootstrapConfig), time.Since(start)) + logger.Debugf("full envoy validation of %d size completed in %s", len(bootstrapConfig), time.Since(start)) if err != nil { if os.IsNotExist(err) { diff --git a/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go b/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go index 97702a250e8..7b19141dc30 100644 --- a/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go +++ b/projects/gateway/pkg/services/k8sadmission/validating_admission_webhook.go @@ -8,6 +8,7 @@ import ( "io" "log" "net/http" + "net/http/httputil" "slices" "time" @@ -227,6 +228,9 @@ func (wh *gatewayValidationWebhook) ServeHTTP(w http.ResponseWriter, r *http.Req logger.Debug("received validation request on webhook") + b, _ := httputil.DumpRequest(r, true) + logger.Debugf("validation request dump:\n %s", string(b)) + // Verify the content type is accurate contentType := r.Header.Get("Content-Type") if contentType != ApplicationJson && contentType != ApplicationYaml { diff --git a/test/kubernetes/testutils/assertions/deployments.go b/test/kubernetes/testutils/assertions/deployments.go index 1012c6952e9..ea36c94c561 100644 --- a/test/kubernetes/testutils/assertions/deployments.go +++ b/test/kubernetes/testutils/assertions/deployments.go @@ -11,6 +11,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/types" + "go.uber.org/zap/zapcore" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -41,7 +42,7 @@ func (p *Provider) EventuallyGlooReachesConsistentState(installNamespace string) // Gloo components are configured to log to the Info level by default but for these e2e tests we explicitly enable debug logging // This is done so we can triage failures after the fact and matches the process users will take to troubleshoot - //logLevelAssertion := assertions.LogLevelAssertion(zapcore.DebugLevel) + logLevelAssertion := assertions.LogLevelAssertion(zapcore.DebugLevel) // The emitter at some point should stabilize and not continue to increase the number of snapshots produced // We choose 4 here as a bit of a magic number, but we feel comfortable that if 4 consecutive polls of the metrics @@ -50,7 +51,7 @@ func (p *Provider) EventuallyGlooReachesConsistentState(installNamespace string) emitterMetricAssertion, _ := assertions.IntStatisticReachesConsistentValueAssertion("api_gloosnapshot_gloo_solo_io_emitter_snap_out", identicalResultInARow) assertions.EventuallyStatisticsMatchAssertions(glooStatsForwardConfig, - //logLevelAssertion, + logLevelAssertion, emitterMetricAssertion, ) }