diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index e73b1a5a059d..d4454b618ba3 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -328,7 +328,6 @@ steps: else sudo chown -R azure-pipelines:azure-pipelines ${{ parameters.pathCacheTemp }}/all fi - displayName: "Cache/save (${{ parameters.cacheName}})" condition: and(succeeded(), ne('${{ parameters.cacheName }}', ''), ne(variables.CACHE_RESTORED, 'true')) diff --git a/.azure-pipelines/stage/checks.yml b/.azure-pipelines/stage/checks.yml index 63882b9fa159..b4e650287a23 100644 --- a/.azure-pipelines/stage/checks.yml +++ b/.azure-pipelines/stage/checks.yml @@ -83,6 +83,7 @@ jobs: cacheName: $(CI_TARGET) envoyBuildFilterExample: $(ENVOY_FILTER_EXAMPLE) cacheTestResults: ${{ parameters.cacheTestResults }} + diskspaceHack: true managedAgent: false repoFetchDepth: $(REPO_FETCH_DEPTH) repoFetchTags: $(REPO_FETCH_TAGS) diff --git a/.azure-pipelines/stage/linux.yml b/.azure-pipelines/stage/linux.yml deleted file mode 100644 index ea465a768ae6..000000000000 --- a/.azure-pipelines/stage/linux.yml +++ /dev/null @@ -1,93 +0,0 @@ -parameters: -- name: cacheTestResults - displayName: "Cache test results" - type: boolean - default: true -- name: pool - displayName: "Agent pool" - type: string - default: envoy-x64-small -- name: artifactSuffix - displayName: "Artifact suffix" - type: string - default: -- name: runTests - displayName: "Run release tests" - type: string - default: true -- name: rbe - displayName: "Use RBE" - type: boolean - default: true -- name: timeoutBuild - displayName: "Build timeout" - type: number - default: 120 -- name: bazelBuildExtraOptions - type: string - default: "" -- name: bazelConfigRBE - type: string - default: --config=remote-ci --config=rbe-google --jobs=$(RbeJobs) - -- name: managedAgent - type: boolean - default: false -- name: tmpfsDockerDisabled - type: string - default: '' - - -- name: runBuild - displayName: "Run build" - type: string - default: true - -jobs: -- job: release - displayName: Build and test - condition: | - and(not(canceled()), - eq(${{ parameters.runBuild }}, 'true')) - timeoutInMinutes: ${{ parameters.timeoutBuild }} - pool: ${{ parameters.pool }} - steps: - - bash: | - if [[ "${{ parameters.runTests }}" == "false" ]]; then - CI_TARGET="release.server_only" - else - CI_TARGET="release" - fi - echo "${CI_TARGET}" - echo "##vso[task.setvariable variable=value;isoutput=true]${CI_TARGET}" - name: target - - template: ../ci.yml - parameters: - artifactName: release - managedAgent: ${{ parameters.managedAgent }} - ciTarget: $(target.value) - cacheName: "release" - bazelConfigRBE: ${{ parameters.bazelConfigRBE }} - bazelBuildExtraOptions: ${{ parameters.bazelBuildExtraOptions }} - cacheTestResults: ${{ parameters.cacheTestResults }} - cacheVersion: $(cacheKeyBazel) - artifactSuffix: ${{ parameters.artifactSuffix }} - rbe: ${{ parameters.rbe }} - tmpfsDockerDisabled: ${{ parameters.tmpfsDockerDisabled }} - -- job: released - displayName: Complete - dependsOn: ["release"] - pool: - vmImage: $(agentUbuntu) - # This condition ensures that this (required) job passes if all of - # the preceeding jobs either pass or are skipped - # adapted from: - # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#job-to-job-dependencies-within-one-stage - condition: | - and(eq(variables['Build.Reason'], 'PullRequest'), - in(dependencies.release.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')) - steps: - - checkout: none - - bash: | - echo "linux_x64 released" diff --git a/.azure-pipelines/stage/prechecks.yml b/.azure-pipelines/stage/prechecks.yml index b8bfaed62ab7..c4e2d779a6ba 100644 --- a/.azure-pipelines/stage/prechecks.yml +++ b/.azure-pipelines/stage/prechecks.yml @@ -25,6 +25,15 @@ parameters: type: string default: "" +- name: runBuild + displayName: "Run build" + type: string + default: true +- name: runPrechecks + displayName: "Run prechecks" + type: string + default: true + # Timeout/s - name: timeoutPrechecks type: number @@ -32,10 +41,10 @@ parameters: # a lot of change - eg protobuf changed, or a primitve proto changed. default: 40 -- name: runPrechecks - displayName: "Run prechecks" +- name: bazelConfigRBE type: string - default: true + default: --config=remote-ci --config=rbe-google --jobs=$(RbeJobs) + jobs: - job: prechecks @@ -53,17 +62,21 @@ jobs: matrix: format: CI_TARGET: "format" + CI_CACHE: format protobuf: CI_TARGET: "check_and_fix_proto_format" + CI_CACHE: check_and_fix_proto_format ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: publishing: CI_TARGET: docs + CI_CACHE: docs + steps: - template: ../ci.yml parameters: bazelBuildExtraOptions: --config=docs-ci ciTarget: $(CI_TARGET) - cacheName: $(CI_TARGET) + cacheName: $(CI_CACHE) cacheTestResults: ${{ parameters.cacheTestResults }} cacheVersion: $(cacheKeyBazel) publishEnvoy: false @@ -157,9 +170,47 @@ jobs: GCS_ARTIFACT_BUCKET: ${{ parameters.bucketGCP }} condition: eq(variables['CI_TARGET'], 'docs') +- job: precheck_release_x64 + displayName: Precheck release (x64) + condition: | + and(not(canceled()), + eq(${{ parameters.runBuild }}, 'true')) + timeoutInMinutes: 180 + pool: envoy-x64-large + steps: + - template: ../ci.yml + parameters: + artifactName: release + ciTarget: release.test_only + cacheName: release-test-only + bazelConfigRBE: ${{ parameters.bazelConfigRBE }} + cacheTestResults: ${{ parameters.cacheTestResults }} + cacheVersion: $(cacheKeyBazel) + rbe: true + +- job: precheck_release_arm64 + displayName: Precheck release (arm64) + condition: | + and(not(canceled()), + eq(${{ parameters.runBuild }}, 'true')) + timeoutInMinutes: 180 + pool: envoy-arm-large + steps: + - template: ../ci.yml + parameters: + artifactName: release + ciTarget: release.test_only + cacheName: release-test-only + bazelConfigRBE: ${{ parameters.bazelConfigRBE }} + bazelBuildExtraOptions: "--sandbox_base=/tmp/sandbox_base" + cacheTestResults: ${{ parameters.cacheTestResults }} + cacheVersion: $(cacheKeyBazel) + artifactSuffix: .arm64 + rbe: false + - job: prechecked displayName: Prechecked - dependsOn: ["prechecks"] + dependsOn: ["prechecks", "precheck_release_arm64", "precheck_release_x64"] pool: vmImage: $(agentUbuntu) # This condition ensures that this (required) job passes if all of @@ -169,7 +220,8 @@ jobs: condition: | and( eq(variables['Build.Reason'], 'PullRequest'), - in(dependencies.prechecks.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')) + in(dependencies.prechecks.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'), + in(dependencies.precheck_release_arm64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')) steps: - checkout: none - bash: | diff --git a/.azure-pipelines/stage/publish.yml b/.azure-pipelines/stage/publish.yml index 477c951b16e3..dc1f811cdf63 100644 --- a/.azure-pipelines/stage/publish.yml +++ b/.azure-pipelines/stage/publish.yml @@ -45,6 +45,14 @@ parameters: type: string default: "" +- name: bazelConfigRBE + type: string + default: --config=remote-ci --config=rbe-google --jobs=$(RbeJobs) + +- name: runBuild + displayName: "Run Build" + type: string + default: true - name: runDocker displayName: "Run Docker" type: string @@ -64,8 +72,58 @@ parameters: default: false jobs: + +- job: release_x64 + displayName: Binary release + condition: | + and(not(canceled()), + eq(${{ parameters.runBuild }}, 'true')) + timeoutInMinutes: 120 + pool: + vmImage: $(agentUbuntu) + steps: + - template: ../ci.yml + parameters: + artifactName: release + ciTarget: release.server_only + cacheName: release-server-only + bazelConfigRBE: ${{ parameters.bazelConfigRBE }} + cacheVersion: $(cacheKeyBazel) + cacheTestResults: false + publishTestResults: false + rbe: true + +- job: release_arm64 + displayName: Binary release (arm64) + condition: | + and(not(canceled()), + eq(${{ parameters.runBuild }}, 'true')) + timeoutInMinutes: 180 + pool: envoy-arm-large + steps: + - bash: | + CI_TARGET="release.server_only" + echo "${CI_TARGET}" + echo "##vso[task.setvariable variable=value;isoutput=true]${CI_TARGET}" + name: target + - template: ../ci.yml + parameters: + artifactName: release + ciTarget: release.server_only + cacheName: release-server-only + bazelConfigRBE: ${{ parameters.bazelConfigRBE }} + bazelBuildExtraOptions: "--sandbox_base=/tmp/sandbox_base" + cacheVersion: $(cacheKeyBazel) + cacheTestResults: false + artifactSuffix: .arm64 + publishTestResults: false + rbe: false + - job: docker displayName: "Docker (Linux multi arch)" + dependsOn: + - release_x64 + - release_arm64 condition: | and(not(canceled()), eq(${{ parameters.runDocker }}, 'true')) @@ -128,7 +186,7 @@ jobs: - job: package_x64 displayName: Linux debs (x64) - dependsOn: [] + dependsOn: ["release_x64"] condition: | and(not(canceled()), eq(${{ parameters.runPackaging }}, 'true')) @@ -162,7 +220,7 @@ jobs: - job: package_arm64 displayName: Linux debs (arm64) - dependsOn: [] + dependsOn: ["release_arm64"] condition: | and(not(canceled()), eq(${{ parameters.runPackaging }}, 'true')) diff --git a/.azure-pipelines/stage/verify.yml b/.azure-pipelines/stage/verify.yml deleted file mode 100644 index 20bff07dc7cc..000000000000 --- a/.azure-pipelines/stage/verify.yml +++ /dev/null @@ -1,84 +0,0 @@ -parameters: - -# Auth -- name: authGCP - type: string - default: "" - - -jobs: -- job: packages_x64 - displayName: Debs (x64) - condition: | - and(not(canceled()), - succeeded(), - ne(stageDependencies.env.repo.outputs['changed.mobileOnly'], 'true'), - ne(stageDependencies.env.repo.outputs['changed.docsOnly'], 'true'), - ne(stageDependencies.env.repo.outputs['changed.examplesOnly'], 'true')) - timeoutInMinutes: 120 - pool: envoy-x64-small - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - artifactName: "distribution" - itemPattern: "distribution/x64/packages.x64.tar.gz" - downloadType: single - targetPath: $(Build.StagingDirectory) - - template: ../ci.yml - parameters: - ciTarget: verify_distro - cacheName: verify_distro - publishTestResults: false - tmpfsDockerDisabled: true - env: - ENVOY_DOCKER_IN_DOCKER: 1 - -- job: packages_arm64 - displayName: Debs (arm64) - condition: | - and(not(canceled()), - succeeded(), - ne(stageDependencies.env.repo.outputs['changed.mobileOnly'], 'true'), - ne(stageDependencies.env.repo.outputs['changed.docsOnly'], 'true'), - ne(stageDependencies.env.repo.outputs['changed.examplesOnly'], 'true')) - timeoutInMinutes: 120 - pool: "envoy-arm-small" - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - artifactName: "distribution" - itemPattern: "distribution/arm64/packages.arm64.tar.gz" - downloadType: single - targetPath: $(Build.StagingDirectory) - - template: ../ci.yml - parameters: - managedAgent: false - ciTarget: verify_distro - cacheName: verify_distro - rbe: false - artifactSuffix: ".arm64" - publishTestResults: false - tmpfsDockerDisabled: true - env: - ENVOY_DOCKER_IN_DOCKER: 1 - -- job: verified - displayName: Verification complete - dependsOn: ["packages_x64", "packages_arm64"] - pool: - vmImage: $(agentUbuntu) - # This condition ensures that this (required) check passes if all of - # the preceding checks either pass or are skipped - # adapted from: - # https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#job-to-job-dependencies-within-one-stage - condition: | - and( - eq(variables['Build.Reason'], 'PullRequest'), - in(dependencies.packages_x64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'), - in(dependencies.packages_arm64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')) - steps: - - checkout: none - - bash: | - echo "checks complete" diff --git a/.azure-pipelines/stages.yml b/.azure-pipelines/stages.yml index f4ab9607aa06..72438bf0ab46 100644 --- a/.azure-pipelines/stages.yml +++ b/.azure-pipelines/stages.yml @@ -12,7 +12,7 @@ parameters: type: object default: - env - - linux_x64 + - prechecks - name: concurrencyChecks displayName: "Check concurrency" type: number @@ -59,40 +59,6 @@ stages: bucketGCP: $(GcsArtifactBucket) runPrechecks: stageDependencies.env.repo.outputs['run.releaseTests'] -- stage: linux_x64 - displayName: Linux x64 - dependsOn: ${{ parameters.buildStageDeps }} - variables: - RUN_BUILD: $[stageDependencies.env.repo.outputs['run.build']] - RUN_TESTS: $[stageDependencies.env.repo.outputs['run.releaseTests']] - jobs: - - template: stage/linux.yml - parameters: - cacheTestResults: ${{ parameters.cacheTestResults }} - bazelConfigRBE: --config=remote-ci --config=rbe-google --jobs=200 - pool: envoy-x64-large - # these are parsed differently and _must_ be expressed in this way - runBuild: variables['RUN_BUILD'] - runTests: $(RUN_TESTS) - -- stage: linux_arm64 - displayName: Linux arm64 - dependsOn: ${{ parameters.buildStageDeps }} - variables: - RUN_BUILD: $[stageDependencies.env.repo.outputs['run.build']] - RUN_TESTS: $[stageDependencies.env.repo.outputs['run.releaseTests']] - jobs: - - template: stage/linux.yml - parameters: - cacheTestResults: ${{ parameters.cacheTestResults }} - rbe: false - artifactSuffix: .arm64 - timeoutBuild: 180 - pool: envoy-arm-large - runBuild: variables['RUN_BUILD'] - runTests: $(RUN_TESTS) - bazelBuildExtraOptions: "--sandbox_base=/tmp/sandbox_base" - - stage: check displayName: Checks (Linux x64) dependsOn: ${{ parameters.checkStageDeps }} @@ -110,8 +76,9 @@ stages: - stage: publish displayName: Publish - dependsOn: ["env", "linux_x64", "linux_arm64"] + dependsOn: ["env", "prechecks"] variables: + RUN_BUILD: $[stageDependencies.env.repo.outputs['run.build']] RUN_DOCKER: $[stageDependencies.env.repo.outputs['run.docker']] RUN_PACKAGING: $[stageDependencies.env.repo.outputs['run.packaging']] PUBLISH_GITHUB_RELEASE: $[stageDependencies.env.repo.outputs['publish.githubRelease']] @@ -131,17 +98,8 @@ stages: bucketGCP: $(GcsArtifactBucket) timeoutDockerBuild: ${{ parameters.timeoutDockerBuild }} timeoutDockerPublish: ${{ parameters.timeoutDockerPublish }} + runBuild: variables['RUN_BUILD'] runDocker: variables['RUN_DOCKER'] runPackaging: variables['RUN_PACKAGING'] publishDockerhub: variables['PUBLISH_DOCKERHUB'] publishGithubRelease: variables['PUBLISH_GITHUB_RELEASE'] - -- stage: verify - displayName: Verify - dependsOn: ["env", "publish"] - variables: - RUN_DOCKER: $[stageDependencies.env.repo.outputs['run.docker']] - jobs: - - template: stage/verify.yml - parameters: - authGCP: $(GcpServiceAccountKey) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c9d1d9ac09c1..eaebf612ac58 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,46 +9,6 @@ updates: # # Please ensure any new ones are added here, and any that are removed are removed here also. -- package-ecosystem: "pip" - directory: "/examples/grpc-bridge/client" - groups: - examples-grpc-bridge: - patterns: - - "*" - schedule: - interval: "daily" - time: "06:00" - -- package-ecosystem: "pip" - directory: "/examples/cache" - groups: - examples-cache: - patterns: - - "*" - schedule: - interval: "daily" - time: "06:00" - -- package-ecosystem: "pip" - directory: "/examples/shared/python/aiohttp" - groups: - examples-shared-python: - patterns: - - "*" - schedule: - interval: "daily" - time: "06:00" - -- package-ecosystem: "pip" - directory: "/examples/shared/python/postgres" - groups: - examples-postgres: - patterns: - - "*" - schedule: - interval: "daily" - time: "06:00" - - package-ecosystem: "pip" directory: "/tools/base" open-pull-requests-limit: 20 @@ -68,153 +28,6 @@ updates: interval: daily time: "06:00" -- package-ecosystem: "docker" - directory: "/examples/ext_authz" - groups: - examples-ext-authz: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/fault-injection" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/golang-network" - groups: - examples-golang-network: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/grpc-bridge" - groups: - examples-grpc-bridge: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/kafka" - groups: - examples-kafka: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/local_ratelimit" - groups: - examples-local-ratelimit: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/mysql" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/opentelemetry" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/redis" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/build" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/echo" - schedule: - interval: daily - time: "06:00" - -# TODO(phlax): just use above -- package-ecosystem: "docker" - directory: "/examples/shared/echo2" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/golang" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/jaeger" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/node" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/postgres" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/python" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/shared/websocket" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/skywalking" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/udp" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "docker" - directory: "/examples/zipkin" - schedule: - interval: daily - time: "06:00" - - package-ecosystem: "github-actions" directory: "/" schedule: @@ -348,59 +161,3 @@ updates: schedule: interval: daily time: "06:00" - -- package-ecosystem: "gomod" - directory: "/examples/ext_authz/auth/grpc-service" - groups: - examples-ext-authz: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "gomod" - directory: "/examples/load-reporting-service" - groups: - examples-load-reporting: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "gomod" - directory: "/examples/grpc-bridge/server" - groups: - examples-grpc-bridge: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "gomod" - directory: "/examples/golang-http/simple" - groups: - examples-golang-http: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "gomod" - directory: "/examples/golang-network/simple" - groups: - examples-golang-network: - patterns: - - "*" - schedule: - interval: daily - time: "06:00" - -- package-ecosystem: "npm" - directory: "/examples/single-page-app/ui" - schedule: - interval: daily - time: "06:00" diff --git a/.github/workflows/_cache.yml b/.github/workflows/_cache.yml index bc2b7658f80d..a30cf01df779 100644 --- a/.github/workflows/_cache.yml +++ b/.github/workflows/_cache.yml @@ -11,12 +11,21 @@ on: app-key: required: true inputs: + arch: + type: string + default: x64 + cache-suffix: + type: string + default: image-tag: type: string required: true request: type: string required: true + runs-on: + type: string + default: ubuntu-24.04 lock-repository: type: string default: envoyproxy/ci-mutex @@ -29,7 +38,7 @@ on: # For a job that does, you can restore with something like: # # steps: -# - uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.30 +# - uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.35 # with: # key: "${{ needs.env.outputs.build-image }}" # @@ -37,33 +46,34 @@ on: jobs: docker: - runs-on: ubuntu-22.04 + runs-on: ${{ inputs.runs-on || 'ubuntu-24.04' }} steps: - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 id: appauth name: Appauth (mutex lock) with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/docker/cache/prime@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/docker/cache/prime@actions-v0.2.35 id: docker - name: Prime Docker cache (${{ inputs.image-tag }}) + name: Prime Docker cache (${{ inputs.image-tag }}${{ inputs.cache-suffix }}) with: image-tag: ${{ inputs.image-tag }} + key-suffix: ${{ inputs.cache-suffix }} lock-token: ${{ steps.appauth.outputs.token }} lock-repository: ${{ inputs.lock-repository }} - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: data name: Cache data with: input-format: yaml input: | cached: ${{ steps.docker.outputs.cached }} - key: ${{ inputs.image-tag }} - - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.31 + key: ${{ inputs.image-tag }}${{ inputs.cache-suffix }} + - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.35 name: Summary with: json: ${{ steps.data.outputs.value }} output-path: GITHUB_STEP_SUMMARY title: >- - Cache (Docker x64) + Cache (Docker ${{ inputs.arch }}) diff --git a/.github/workflows/_finish.yml b/.github/workflows/_finish.yml index 8ef40d156571..62a7a884b05e 100644 --- a/.github/workflows/_finish.yml +++ b/.github/workflows/_finish.yml @@ -36,7 +36,7 @@ jobs: actions: read contents: read steps: - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 name: Incoming data id: needs with: @@ -87,7 +87,7 @@ jobs: summary: "Check has finished", text: $text}}}} - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 name: Print summary with: input: ${{ toJSON(steps.needs.outputs.value).summary-title }} @@ -95,13 +95,13 @@ jobs: "## \(.)" options: -Rr output-path: GITHUB_STEP_SUMMARY - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.35 name: Update check with: action: update diff --git a/.github/workflows/_load.yml b/.github/workflows/_load.yml index 4f16bf83aa89..85991ba4baaa 100644 --- a/.github/workflows/_load.yml +++ b/.github/workflows/_load.yml @@ -91,7 +91,7 @@ jobs: # Handle any failure in triggering job # Remove any `checks` we dont care about # Prepare a check request - - uses: envoyproxy/toolshed/gh-actions/github/env/load@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/env/load@actions-v0.2.35 name: Load env id: data with: @@ -102,13 +102,13 @@ jobs: GH_TOKEN: ${{ github.token }} # Update the check - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.35 name: Update check if: ${{ fromJSON(steps.data.outputs.data).data.check.action == 'RUN' }} with: @@ -116,7 +116,7 @@ jobs: checks: ${{ toJSON(fromJSON(steps.data.outputs.data).checks) }} token: ${{ steps.appauth.outputs.token }} - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 name: Print request summary with: input: | @@ -136,7 +136,7 @@ jobs: | $summary.summary as $summary | "${{ inputs.template-request-summary }}" - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: request-output name: Load request with: @@ -157,9 +157,25 @@ jobs: secrets: app-id: ${{ secrets.lock-app-id }} app-key: ${{ secrets.lock-app-key }} - uses: ./.github/workflows/_cache.yml + name: ${{ matrix.name || matrix.target }} needs: request + uses: ./.github/workflows/_cache.yml if: ${{ inputs.cache-docker && ! fromJSON(needs.request.outputs.skip) }} with: - request: ${{ toJSON(needs.request.outputs) }} + arch: ${{ matrix.arch }} + cache-suffix: ${{ matrix.cache-suffix }} image-tag: ${{ fromJSON(needs.request.outputs.build-image).default }} + request: ${{ toJSON(needs.request.outputs) }} + runs-on: ${{ matrix.runs-on }} + strategy: + fail-fast: false + matrix: + include: + - target: docker-x64 + name: Docker (x64) + arch: x64 + - target: docker-arm64 + name: Docker (arm64) + arch: arm64 + cache-suffix: -arm64 + runs-on: envoy-arm64-small diff --git a/.github/workflows/_load_env.yml b/.github/workflows/_load_env.yml index 988b8669eba6..6c9f4f7d5ded 100644 --- a/.github/workflows/_load_env.yml +++ b/.github/workflows/_load_env.yml @@ -63,18 +63,18 @@ jobs: request: ${{ steps.env.outputs.data }} trusted: true steps: - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: started name: Create timestamp with: options: -r filter: | now - - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 id: checkout name: Checkout Envoy repository - name: Generate environment variables - uses: envoyproxy/toolshed/gh-actions/envoy/ci/env@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/envoy/ci/env@actions-v0.2.35 id: env with: branch-name: ${{ inputs.branch-name }} @@ -86,7 +86,7 @@ jobs: - name: Request summary id: summary - uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.35 with: actor: ${{ toJSON(fromJSON(steps.env.outputs.data).request.actor) }} base-sha: ${{ fromJSON(steps.env.outputs.data).request.base-sha }} diff --git a/.github/workflows/_stage_publish.yml b/.github/workflows/_publish_publish.yml similarity index 99% rename from .github/workflows/_stage_publish.yml rename to .github/workflows/_publish_publish.yml index 5bcc3a48d16d..be26f8bdff4c 100644 --- a/.github/workflows/_stage_publish.yml +++ b/.github/workflows/_publish_publish.yml @@ -63,7 +63,7 @@ jobs: export ENVOY_PUBLISH_DRY_RUN=${{ (fromJSON(inputs.request).request.version.dev || ! inputs.trusted) && 1 || '' }} steps-pre: | - id: url - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.30 + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 with: options: -Rr input: >- @@ -80,7 +80,7 @@ jobs: end | . as $bucket | "https://storage.googleapis.com/\($bucket)/\($sha)/\($path)" - - uses: envoyproxy/toolshed/gh-actions/fetch@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/fetch@actions-v0.2.35 with: url: %{{ steps.url.outputs.value }} path: %{{ runner.temp }}/release.signed @@ -98,12 +98,12 @@ jobs: needs: - publish steps: - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 id: appauth with: app_id: ${{ secrets.ENVOY_CI_SYNC_APP_ID }} key: ${{ secrets.ENVOY_CI_SYNC_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.35 with: ref: main repository: ${{ fromJSON(inputs.request).request.version.dev && 'envoyproxy/envoy-website' || 'envoyproxy/archive' }} diff --git a/.github/workflows/_publish_verify.yml b/.github/workflows/_publish_verify.yml new file mode 100644 index 000000000000..075e4aad0440 --- /dev/null +++ b/.github/workflows/_publish_verify.yml @@ -0,0 +1,166 @@ +name: Verify + +permissions: + contents: read + +on: + workflow_call: + inputs: + request: + type: string + required: true + trusted: + type: boolean + required: true + +concurrency: + group: >- + ${{ github.actor != 'trigger-release-envoy[bot]' + && github.event.inputs.head_ref + || github.run_id + }}-${{ github.event.workflow.id }}-verify + cancel-in-progress: true + + +jobs: + verify-examples: + permissions: + contents: read + packages: read + name: ${{ matrix.name || matrix.target }} + uses: ./.github/workflows/_run.yml + with: + bazel-extra: ${{ matrix.bazel-extra || '--config=rbe-envoy-engflow' }} + cache-build-image: ${{ matrix.cache-build-image }} + cache-build-image-key-suffix: ${{ matrix.arch == 'arm64' && format('-{0}', matrix.arch) || '' }} + container-command: ${{ matrix.container-command }} + concurrency-suffix: -${{ matrix.arch || 'x64' }} + rbe: ${{ matrix.rbe }} + request: ${{ inputs.request }} + runs-on: ${{ matrix.runs-on || 'ubuntu-24.04' }} + steps-pre: ${{ matrix.steps-pre }} + source: ${{ matrix.source }} + target: ${{ matrix.target }} + trusted: ${{ inputs.trusted }} + strategy: + fail-fast: false + matrix: + include: + - name: examples + target: verify_examples + rbe: false + source: | + export NO_BUILD_SETUP=1 + steps-pre: | + - run: | + # Install expected host packages + export DEBIAN_FRONTEND=noninteractive + sudo apt-get -qq update -y + sudo apt-get -qq install -y --no-install-recommends expect gettext yq whois + shell: bash + - id: url + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 + with: + options: -Rr + input: >- + ${{ inputs.trusted + && fromJSON(inputs.request).request.sha + || fromJSON(inputs.request).request.ref }} + filter: | + .[:7] as $sha + | if ${{ inputs.trusted }} then + "envoy-postsubmit" + else + "envoy-pr" + end + | . as $bucket + | "https://storage.googleapis.com/\($bucket)/\($sha)" + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.35 + with: + url: %{{ steps.url.outputs.value }}/docker/envoy.tar + variant: dev + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.35 + with: + url: %{{ steps.url.outputs.value }}/docker/envoy-contrib.tar + variant: contrib-dev + - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.35 + with: + url: %{{ steps.url.outputs.value }}/docker/envoy-google-vrp.tar + variant: google-vrp-dev + - run: docker images | grep envoy + shell: bash + + verify-distro: + permissions: + contents: read + packages: read + name: ${{ matrix.name || matrix.target }} + uses: ./.github/workflows/_run.yml + with: + bazel-extra: ${{ matrix.bazel-extra || '--config=rbe-envoy-engflow' }} + cache-build-image: ${{ fromJSON(inputs.request).request.build-image.default }} + cache-build-image-key-suffix: ${{ matrix.arch == 'arm64' && format('-{0}', matrix.arch) || '' }} + container-command: ./ci/run_envoy_docker.sh + concurrency-suffix: -${{ matrix.arch || 'x64' }} + rbe: ${{ matrix.rbe && matrix.rbe || false }} + request: ${{ inputs.request }} + runs-on: ${{ matrix.runs-on || 'ubuntu-24.04' }} + source: | + export NO_BUILD_SETUP=1 + export ENVOY_DOCKER_IN_DOCKER=1 + target: ${{ matrix.target }} + trusted: ${{ inputs.trusted }} + steps-pre: | + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.30 + id: url + with: + options: -Rr + input: >- + ${{ inputs.trusted + && fromJSON(inputs.request).request.sha + || fromJSON(inputs.request).request.ref }} + filter: | + .[:7] as $sha + | if ${{ inputs.trusted }} then + "envoy-postsubmit" + else + "envoy-pr" + end + | . as $bucket + | "https://storage.googleapis.com/\($bucket)/\($sha)/release/release.signed.tar.zst" + - uses: envoyproxy/toolshed/gh-actions/fetch@actions-v0.2.30 + id: fetch + with: + url: %{{ steps.url.outputs.value }} + - run: | + echo ARCH=${{ matrix.arch || 'x64' }} >> $GITHUB_ENV + echo DEB_ARCH=${{ matrix.arch != 'arm64' && 'amd64' || 'arm64' }} >> $GITHUB_ENV + shell: bash + - run: | + TEMP_DIR=$(mktemp -d) + zstd --stdout -d %{{ steps.fetch.outputs.path }} | tar --warning=no-timestamp -xf - -C "${TEMP_DIR}" + mkdir ${TEMP_DIR}/debs + tar xf ${TEMP_DIR}/bin/debs.tar.gz -C ${TEMP_DIR}/debs + mkdir -p ${TEMP_DIR}/distribution/deb + cp -a ${TEMP_DIR}/debs/*_${DEB_ARCH}* ${TEMP_DIR}/distribution/deb + cp -a ${TEMP_DIR}/signing.key ${TEMP_DIR}/distribution + mkdir -p %{{ runner.temp }}/distribution/${ARCH} + tar czf %{{ runner.temp }}/distribution/${ARCH}/packages.${ARCH}.tar.gz -C ${TEMP_DIR}/distribution . + shell: bash + + strategy: + fail-fast: false + matrix: + include: + + - name: verify_distro_x64 + target: verify_distro + rbe: true + + - name: verify_distro_arm64 + target: verify_distro + arch: arm64 + bazel-extra: >- + --config=cache-envoy-engflow + --config=bes-envoy-engflow + runs-on: envoy-arm64-small diff --git a/.github/workflows/_request.yml b/.github/workflows/_request.yml index b992ddadf00a..1b44ae81019a 100644 --- a/.github/workflows/_request.yml +++ b/.github/workflows/_request.yml @@ -40,14 +40,14 @@ jobs: env: ${{ steps.data.outputs.value }} config: ${{ steps.config.outputs.config }} steps: - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: started name: Create timestamp with: options: -r filter: | now - - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 id: checkout name: Checkout Envoy repository with: @@ -60,7 +60,7 @@ jobs: # *ALL* variables collected should be treated as untrusted and should be sanitized before # use - name: Generate environment variables from commit - uses: envoyproxy/toolshed/gh-actions/envoy/ci/request@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/envoy/ci/request@actions-v0.2.35 id: env with: branch-name: ${{ steps.checkout.outputs.branch-name }} @@ -71,7 +71,7 @@ jobs: vars: ${{ toJSON(vars) }} - name: Request summary id: summary - uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/env/summary@actions-v0.2.35 with: actor: ${{ toJSON(fromJSON(steps.env.outputs.data).request.actor) }} base-sha: ${{ fromJSON(steps.env.outputs.data).request.base-sha }} @@ -87,7 +87,7 @@ jobs: target-branch: ${{ fromJSON(steps.env.outputs.data).request.target-branch }} - name: Environment data - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: data with: input: | diff --git a/.github/workflows/_run.yml b/.github/workflows/_run.yml index 993114d2a11b..e65e87a4e2cb 100644 --- a/.github/workflows/_run.yml +++ b/.github/workflows/_run.yml @@ -21,11 +21,16 @@ on: default: 75 cache-build-image: type: string + cache-build-image-key-suffix: + type: string catch-errors: type: boolean default: false checkout-extra: type: string + concurrency-suffix: + type: string + default: container-command: type: string default: ./ci/run_envoy_docker.sh @@ -96,7 +101,7 @@ on: summary-post: type: string default: | - - uses: envoyproxy/toolshed/gh-actions/envoy/run/summary@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/run/summary@actions-v0.2.35 with: context: %{{ inputs.context }} steps-pre: @@ -141,7 +146,7 @@ concurrency: ${{ github.actor != 'trigger-release-envoy[bot]' && github.head_ref || github.run_id - }}-${{ github.workflow }}-${{ inputs.target }} + }}-${{ github.workflow }}-${{ inputs.target }}${{ inputs.concurrency-suffix }} cancel-in-progress: true env: @@ -158,7 +163,7 @@ jobs: name: ${{ inputs.command }} ${{ inputs.target }} timeout-minutes: ${{ inputs.timeout-minutes }} steps: - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: started name: Create timestamp with: @@ -166,7 +171,7 @@ jobs: filter: | now # This controls which input vars are exposed to the run action (and related steps) - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 name: Context id: context with: @@ -187,11 +192,12 @@ jobs: | . * {$config, $check} - if: ${{ inputs.cache-build-image }} name: Restore Docker cache ${{ inputs.cache-build-image && format('({0})', inputs.cache-build-image) || '' }} - uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/docker/cache/restore@actions-v0.2.35 with: image_tag: ${{ inputs.cache-build-image }} + key-suffix: ${{ inputs.cache-build-image-key-suffix }} - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 id: appauth name: Appauth if: ${{ inputs.trusted }} @@ -202,7 +208,7 @@ jobs: # - the workaround is to allow the token to be passed through. token: ${{ github.token }} token-ok: true - - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 id: checkout name: Checkout Envoy repository with: @@ -219,7 +225,7 @@ jobs: token: ${{ inputs.trusted && steps.appauth.outputs.token || github.token }} # This is currently only use by mobile-docs and can be removed once they are updated to the newer website - - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 id: checkout-extra name: Checkout extra repository (for publishing) if: ${{ inputs.checkout-extra }} @@ -227,7 +233,7 @@ jobs: config: ${{ inputs.checkout-extra }} ssh-key: ${{ inputs.trusted && inputs.ssh-key-extra || '' }} - - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.35 name: Run CI ${{ inputs.command }} ${{ inputs.target }} with: args: ${{ inputs.args != '--' && inputs.args || inputs.target }} @@ -259,11 +265,11 @@ jobs: env: GITHUB_TOKEN: ${{ inputs.trusted && steps.appauth.outputs.token || github.token }} ENVOY_DOCKER_BUILD_DIR: ${{ runner.temp }} - ENVOY_RBE: ${{ inputs.rbe != 'false' && 1 || '' }} + ENVOY_RBE: ${{ inputs.rbe == true && 1 || '' }} RBE_KEY: ${{ secrets.rbe-key }} BAZEL_BUILD_EXTRA_OPTIONS: >- --config=remote-ci ${{ inputs.bazel-extra }} - ${{ inputs.rbe != 'false' && format('--jobs={0}', inputs.bazel-rbe-jobs) || '' }} + ${{ inputs.rbe == true && format('--jobs={0}', inputs.bazel-rbe-jobs) || '' }} BAZEL_FAKE_SCM_REVISION: ${{ github.event_name == 'pull_request' && 'e3b4a6e9570da15ac1caffdded17a8bebdc7dfc9' || '' }} CI_TARGET_BRANCH: ${{ fromJSON(inputs.request).request.target-branch }} diff --git a/.github/workflows/_stage_verify.yml b/.github/workflows/_stage_verify.yml deleted file mode 100644 index c6de8a7c1bf6..000000000000 --- a/.github/workflows/_stage_verify.yml +++ /dev/null @@ -1,107 +0,0 @@ -name: Verify - -permissions: - contents: read - -on: - workflow_call: - inputs: - request: - type: string - required: true - trusted: - type: boolean - required: true - -concurrency: - group: >- - ${{ github.actor != 'trigger-release-envoy[bot]' - && github.event.inputs.head_ref - || github.run_id - }}-${{ github.event.workflow.id }}-verify - cancel-in-progress: true - - -jobs: - verify: - permissions: - contents: read - packages: read - name: ${{ matrix.name || matrix.target }} - uses: ./.github/workflows/_run.yml - with: - cache-build-image: - container-command: - rbe: ${{ matrix.rbe }} - request: ${{ inputs.request }} - runs-on: envoy-x64-small - steps-pre: ${{ matrix.steps-pre }} - source: ${{ matrix.source }} - target: ${{ matrix.target }} - trusted: ${{ inputs.trusted }} - strategy: - fail-fast: false - matrix: - include: - - name: examples - target: verify_examples - source: | - export NO_BUILD_SETUP=1 - rbe: false - steps-pre: | - - run: | - # TODO(phlax): Remove this once resolved properly - # Downgrade Docker to workaround https://github.com/containers/skopeo/issues/2365 - sudo install -m 0755 -d /etc/apt/keyrings - sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc - sudo chmod a+r /etc/apt/keyrings/docker.asc - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ - https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ - | sudo tee /etc/apt/sources.list.d/docker.list \ - > /dev/null - sudo apt-get update - sudo apt-get install -y -qq --allow-downgrades \ - docker-ce=5:24.0.9-1~ubuntu.22.04~jammy \ - docker-ce-cli=5:24.0.9-1~ubuntu.22.04~jammy - sudo systemctl restart docker - sudo docker --version - shell: bash - - id: url - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.30 - with: - options: -Rr - input: >- - ${{ inputs.trusted - && fromJSON(inputs.request).request.sha - || fromJSON(inputs.request).request.ref }} - filter: | - .[:7] as $sha - | if ${{ inputs.trusted }} then - "envoy-postsubmit" - else - "envoy-pr" - end - | . as $bucket - | "https://storage.googleapis.com/\($bucket)/\($sha)" - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.30 - with: - url: %{{ steps.url.outputs.value }}/docker/envoy.tar - variant: dev - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.30 - with: - url: %{{ steps.url.outputs.value }}/docker/envoy-contrib.tar - variant: contrib-dev - - uses: envoyproxy/toolshed/gh-actions/docker/fetch@actions-v0.2.30 - with: - url: %{{ steps.url.outputs.value }}/docker/envoy-google-vrp.tar - variant: google-vrp-dev - - run: docker images | grep envoy - shell: bash - - run: | - # Install expected host packages - export DEBIAN_FRONTEND=noninteractive - sudo apt-get -qq update -y - sudo apt-get -qq install -y --no-install-recommends expect gettext whois - pip install -r ./.github/workflows/verify-requirements.txt - shell: bash diff --git a/.github/workflows/_start.yml b/.github/workflows/_start.yml index 928cbf774b45..9b475214da3b 100644 --- a/.github/workflows/_start.yml +++ b/.github/workflows/_start.yml @@ -54,7 +54,7 @@ jobs: start: runs-on: ubuntu-22.04 steps: - - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/jq@actions-v0.2.35 id: check-config name: Prepare check data with: @@ -77,13 +77,13 @@ jobs: | .skipped.output.summary = "${{ inputs.skipped-summary }}" | .skipped.output.text = "" - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 name: Appauth id: appauth with: app_id: ${{ secrets.app-id }} key: ${{ secrets.app-key }} - - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checks@actions-v0.2.35 name: Start checks id: checks with: @@ -94,7 +94,7 @@ jobs: ${{ fromJSON(inputs.env).summary.summary }} token: ${{ steps.appauth.outputs.token }} - - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/json/table@actions-v0.2.35 name: Summary with: collapse-open: true @@ -118,7 +118,7 @@ jobs: output-path: GITHUB_STEP_SUMMARY title: Checks started/skipped - - uses: envoyproxy/toolshed/gh-actions/github/env/save@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/env/save@actions-v0.2.35 name: Save env id: data with: diff --git a/.github/workflows/codeql-daily.yml b/.github/workflows/codeql-daily.yml index 2fa30e48687d..a1d208e6feea 100644 --- a/.github/workflows/codeql-daily.yml +++ b/.github/workflows/codeql-daily.yml @@ -30,11 +30,11 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Free disk space - uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.35 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # codeql-bundle-v3.25.15 + uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # codeql-bundle-v3.26.0 # Override language selection by uncommenting this and choosing your languages with: languages: cpp @@ -68,4 +68,4 @@ jobs: git clean -xdf - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # codeql-bundle-v3.25.15 + uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # codeql-bundle-v3.26.0 diff --git a/.github/workflows/codeql-push.yml b/.github/workflows/codeql-push.yml index f701b13ae904..5a763a564744 100644 --- a/.github/workflows/codeql-push.yml +++ b/.github/workflows/codeql-push.yml @@ -61,11 +61,11 @@ jobs: - name: Free disk space if: ${{ env.BUILD_TARGETS != '' }} - uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/diskspace@actions-v0.2.35 - name: Initialize CodeQL if: ${{ env.BUILD_TARGETS != '' }} - uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # codeql-bundle-v3.25.15 + uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # codeql-bundle-v3.26.0 with: languages: cpp @@ -109,4 +109,4 @@ jobs: - name: Perform CodeQL Analysis if: ${{ env.BUILD_TARGETS != '' }} - uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # codeql-bundle-v3.25.15 + uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # codeql-bundle-v3.26.0 diff --git a/.github/workflows/command.yml b/.github/workflows/command.yml index 89107f990d51..99f78cc63d4f 100644 --- a/.github/workflows/command.yml +++ b/.github/workflows/command.yml @@ -28,7 +28,7 @@ jobs: && github.actor != 'dependabot[bot]' }} steps: - - uses: envoyproxy/toolshed/gh-actions/github/command@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/command@actions-v0.2.35 name: Parse command from comment id: command with: @@ -37,14 +37,14 @@ jobs: ^/(retest) # /retest - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 if: ${{ steps.command.outputs.command == 'retest' }} id: appauth-retest name: Appauth (retest) with: key: ${{ secrets.ENVOY_CI_APP_KEY }} app_id: ${{ secrets.ENVOY_CI_APP_ID }} - - uses: envoyproxy/toolshed/gh-actions/retest@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/retest@actions-v0.2.35 if: ${{ steps.command.outputs.command == 'retest' }} name: Retest with: diff --git a/.github/workflows/envoy-dependency.yml b/.github/workflows/envoy-dependency.yml index cc1521ae54b0..0bab604492e2 100644 --- a/.github/workflows/envoy-dependency.yml +++ b/.github/workflows/envoy-dependency.yml @@ -53,16 +53,16 @@ jobs: steps: - id: appauth name: Appauth - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 with: app_id: ${{ secrets.ENVOY_CI_DEP_APP_ID }} key: ${{ secrets.ENVOY_CI_DEP_APP_KEY }} - id: checkout name: Checkout Envoy repository - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 with: token: ${{ steps.appauth.outputs.token }} - - uses: envoyproxy/toolshed/gh-actions/bson@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/bson@actions-v0.2.35 id: update name: Update dependency (${{ inputs.dependency }}) with: @@ -97,13 +97,13 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: envoyproxy/toolshed/gh-actions/upload/diff@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/upload/diff@actions-v0.2.35 name: Upload diff with: name: ${{ inputs.dependency }}-${{ steps.update.outputs.output }} - name: Create a PR if: ${{ inputs.pr }} - uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.35 with: base: main body: | @@ -134,11 +134,11 @@ jobs: steps: - id: appauth name: Appauth - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 with: app_id: ${{ secrets.ENVOY_CI_DEP_APP_ID }} key: ${{ secrets.ENVOY_CI_DEP_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 id: checkout name: Checkout Envoy repository with: @@ -180,7 +180,7 @@ jobs: - name: Check Docker SHAs id: build-images - uses: envoyproxy/toolshed/gh-actions/docker/shas@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/docker/shas@actions-v0.2.35 with: images: | sha: envoyproxy/envoy-build-ubuntu:${{ steps.build-tools.outputs.tag }} @@ -209,7 +209,7 @@ jobs: name: Update SHAs working-directory: envoy - name: Create a PR - uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.35 with: base: main body: Created by Envoy dependency bot diff --git a/.github/workflows/envoy-publish.yml b/.github/workflows/envoy-publish.yml index ab7a7b896292..df33cd5221ba 100644 --- a/.github/workflows/envoy-publish.yml +++ b/.github/workflows/envoy-publish.yml @@ -62,7 +62,7 @@ jobs: if: ${{ fromJSON(needs.load.outputs.request).run.publish }} needs: - load - uses: ./.github/workflows/_stage_publish.yml + uses: ./.github/workflows/_publish_publish.yml name: Publish with: request: ${{ needs.load.outputs.request }} @@ -75,7 +75,7 @@ jobs: if: ${{ fromJSON(needs.load.outputs.request).run.verify }} needs: - load - uses: ./.github/workflows/_stage_verify.yml + uses: ./.github/workflows/_publish_verify.yml name: Verify with: request: ${{ needs.load.outputs.request }} diff --git a/.github/workflows/envoy-release.yml b/.github/workflows/envoy-release.yml index 777f35c1384c..104df712e7e1 100644 --- a/.github/workflows/envoy-release.yml +++ b/.github/workflows/envoy-release.yml @@ -55,14 +55,14 @@ jobs: steps: - id: appauth name: App auth - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 with: app_id: ${{ secrets.ENVOY_CI_PUBLISH_APP_ID }} key: ${{ secrets.ENVOY_CI_PUBLISH_APP_KEY }} - id: checkout name: Checkout Envoy repository - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 with: committer-name: ${{ env.COMMITTER_NAME }} committer-email: ${{ env.COMMITTER_EMAIL }} @@ -83,10 +83,10 @@ jobs: name: Check changelog summary - if: ${{ inputs.author }} name: Validate signoff email - uses: envoyproxy/toolshed/gh-actions/email/validate@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/email/validate@actions-v0.2.35 with: email: ${{ inputs.author }} - - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.35 name: Create release with: source: | @@ -111,7 +111,7 @@ jobs: name: Release version id: release - name: Create a PR - uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.35 with: base: ${{ github.ref_name }} commit: false @@ -136,20 +136,20 @@ jobs: steps: - id: appauth name: App auth - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 with: app_id: ${{ secrets.ENVOY_CI_PUBLISH_APP_ID }} key: ${{ secrets.ENVOY_CI_PUBLISH_APP_KEY }} - id: checkout name: Checkout Envoy repository - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 with: committer-name: ${{ env.COMMITTER_NAME }} committer-email: ${{ env.COMMITTER_EMAIL }} strip-prefix: release/ token: ${{ steps.appauth.outputs.token }} - - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/github/run@actions-v0.2.35 name: Sync version histories with: command: >- @@ -159,7 +159,7 @@ jobs: -- --signoff="${{ env.COMMITTER_NAME }} <${{ env.COMMITTER_EMAIL }}>" - name: Create a PR - uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/pr@actions-v0.2.35 with: append-commit-message: true base: ${{ github.ref_name }} @@ -189,13 +189,13 @@ jobs: steps: - id: appauth name: App auth - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 with: app_id: ${{ secrets.ENVOY_CI_PUBLISH_APP_ID }} key: ${{ secrets.ENVOY_CI_PUBLISH_APP_KEY }} - name: Checkout repository - uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/github/checkout@actions-v0.2.35 with: committer-name: ${{ env.COMMITTER_NAME }} committer-email: ${{ env.COMMITTER_EMAIL }} diff --git a/.github/workflows/envoy-sync.yml b/.github/workflows/envoy-sync.yml index 4b85692f4035..acd3de4ef854 100644 --- a/.github/workflows/envoy-sync.yml +++ b/.github/workflows/envoy-sync.yml @@ -31,12 +31,12 @@ jobs: - data-plane-api - mobile-website steps: - - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/appauth@actions-v0.2.35 id: appauth with: app_id: ${{ secrets.ENVOY_CI_SYNC_APP_ID }} key: ${{ secrets.ENVOY_CI_SYNC_APP_KEY }} - - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.31 + - uses: envoyproxy/toolshed/gh-actions/dispatch@actions-v0.2.35 with: repository: "envoyproxy/${{ matrix.downstream }}" ref: main diff --git a/.github/workflows/garbage.yml b/.github/workflows/garbage.yml index ecca34630557..01783dfd5a70 100644 --- a/.github/workflows/garbage.yml +++ b/.github/workflows/garbage.yml @@ -33,7 +33,7 @@ jobs: pool-id: 17 steps: - name: Remove dead AZP agents (${{ matrix.target }}) - uses: envoyproxy/toolshed/gh-actions/azp/agent-cleanup@actions-v0.2.31 + uses: envoyproxy/toolshed/gh-actions/azp/agent-cleanup@actions-v0.2.35 with: azp-org: cncf azp-token: ${{ secrets.AZP_TOKEN }} diff --git a/.github/workflows/mobile-android_build.yml b/.github/workflows/mobile-android_build.yml index 509ba5eebac5..d262a6f19c95 100644 --- a/.github/workflows/mobile-android_build.yml +++ b/.github/workflows/mobile-android_build.yml @@ -75,9 +75,9 @@ jobs: target: kotlin-hello-world runs-on: envoy-x64-small steps-pre: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.35 steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.35 with: apk: bazel-bin/examples/kotlin/hello_world/hello_envoy_kt.apk app: io.envoyproxy.envoymobile.helloenvoykotlin/.MainActivity @@ -104,7 +104,7 @@ jobs: target: ${{ matrix.target }} runs-on: envoy-x64-small steps-pre: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/pre@actions-v0.2.35 steps-post: ${{ matrix.steps-post }} timeout-minutes: 50 trusted: ${{ fromJSON(needs.load.outputs.trusted) }} @@ -115,7 +115,7 @@ jobs: include: - name: java-hello-world steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.35 with: apk: bazel-bin/examples/java/hello_world/hello_envoy.apk app: io.envoyproxy.envoymobile.helloenvoy/.MainActivity @@ -134,7 +134,7 @@ jobs: --config=mobile-remote-release-clang-android //test/kotlin/apps/baseline:hello_envoy_kt steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.35 with: apk: bazel-bin/test/kotlin/apps/baseline/hello_envoy_kt.apk app: io.envoyproxy.envoymobile.helloenvoybaselinetest/.MainActivity @@ -149,7 +149,7 @@ jobs: --config=mobile-remote-release-clang-android //test/kotlin/apps/experimental:hello_envoy_kt steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/android/post@actions-v0.2.35 with: apk: bazel-bin/test/kotlin/apps/experimental/hello_envoy_kt.apk app: io.envoyproxy.envoymobile.helloenvoyexperimentaltest/.MainActivity diff --git a/.github/workflows/mobile-ios_build.yml b/.github/workflows/mobile-ios_build.yml index a9ed28375056..023eca732056 100644 --- a/.github/workflows/mobile-ios_build.yml +++ b/.github/workflows/mobile-ios_build.yml @@ -86,7 +86,7 @@ jobs: source ./ci/mac_ci_setup.sh ./bazelw shutdown steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.35 with: app: ${{ matrix.app }} args: ${{ matrix.args || '--config=mobile-remote-ci-macos-ios' }} @@ -130,7 +130,7 @@ jobs: source: | source ./ci/mac_ci_setup.sh steps-post: | - - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.30 + - uses: envoyproxy/toolshed/gh-actions/envoy/ios/post@actions-v0.2.35 with: app: ${{ matrix.app }} args: ${{ matrix.args || '--config=mobile-remote-ci-macos-ios' }} diff --git a/.github/workflows/mobile-perf.yml b/.github/workflows/mobile-perf.yml index f0d9d6e97325..02787de5587f 100644 --- a/.github/workflows/mobile-perf.yml +++ b/.github/workflows/mobile-perf.yml @@ -94,8 +94,9 @@ jobs: request: ${{ needs.load.outputs.request }} runs-on: ubuntu-22.04 source: | - strip -s -o dist/main.stripped dist/sizemain/size-main - strip -s -o dist/current.stripped dist/sizecurrent/size-current + mkdir dist + strip -s -o dist/main.stripped /home/runner/work/_temp/dist/sizemain/size-main + strip -s -o dist/current.stripped /home/runner/work/_temp/dist/sizecurrent/size-current zip -9 dist/main.zip dist/main.stripped zip -9 dist/current.zip dist/current.stripped target: size-compare diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 99a10164ed77..0b3ba9d388ad 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -33,13 +33,13 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: sarif_file: results.sarif diff --git a/.github/workflows/verify-requirements.in b/.github/workflows/verify-requirements.in deleted file mode 100644 index 87de2e955af3..000000000000 --- a/.github/workflows/verify-requirements.in +++ /dev/null @@ -1 +0,0 @@ -yq diff --git a/BUILD b/BUILD index 903253c8601c..c7b88cdece13 100644 --- a/BUILD +++ b/BUILD @@ -69,13 +69,6 @@ package_group( ], ) -package_group( - name = "examples_library", - packages = [ - "//examples/...", - ], -) - package_group( name = "mobile_library", packages = [ diff --git a/CODEOWNERS b/CODEOWNERS index 23e833dfa840..0f41ef52037c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -35,6 +35,8 @@ extensions/filters/common/original_src @klarose @mattklein123 /*/extensions/filters/http/jwt_authn @taoxuy @lizan @tyxia @yanavlasov # grpc_field_extraction http filter extension /*/extensions/filters/http/grpc_field_extraction @taoxuy @nareddyt @yanavlasov +# proto_message_logging http filter extension +/*/extensions/filters/http/proto_message_logging @dchakarwarti @taoxuy @yanavlasov # grpc_http1_reverse_bridge http filter extension /*/extensions/filters/http/grpc_http1_reverse_bridge @zuercher @mattklein123 # alts transport socket extension @@ -177,12 +179,16 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123 /*/extensions/matching/input_matchers/runtime_fraction @ravenblackx @sergkir85 # CEL input matcher /*/extensions/matching/input_matchers/cel_matcher @tyxia @yanavlasov +# dynamic metadata input matcher +/*/extensions/matching/input_matchers/metadata @vikaschoudhary16 @kyessenov # environment generic input /*/extensions/matching/common_inputs/environment @donyu @mattklein123 # format string matching /*/extensions/matching/actions/format_string @kyessenov @cpakulski # CEL data input /*/extensions/matching/http/cel_input @tyxia @yanavlasov +# dynamic metadata input +/*/extensions/matching/http/metadata_input @vikaschoudhary16 @kyessenov # user space socket pair, event, connection and listener /*/extensions/io_socket/user_space @kyessenov @lambdai @soulxu /*/extensions/bootstrap/internal_listener @kyessenov @adisuissa @@ -334,6 +340,7 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123 /*/extensions/health_checkers/grpc @zuercher @botengyao /*/extensions/health_checkers/http @zuercher @botengyao /*/extensions/health_checkers/tcp @zuercher @botengyao +/*/extensions/health_checkers/common @zuercher @botengyao # Health check event sinks /*/extensions/health_check/event_sinks/file @botengyao @yanavlasov # IP Geolocation @@ -345,8 +352,8 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123 /*/extensions/filters/http/match_delegate @wbpcode @jstraceski @tyxia # Generic proxy and related extensions /*/extensions/filters/network/generic_proxy/ @wbpcode @soulxu - -/*/extensions/health_checkers/common @zuercher @botengyao +# Dynamic Modules +/*/extensions/dynamic_modules @mattklein123 @mathetake @marc-barry # HTTP credential injector /*/extensions/filters/http/credential_injector @zhaohuabing @kyessenov diff --git a/README.md b/README.md index 247eac04a471..f2f383d5f001 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,14 @@ involved and how Envoy plays a role, read the CNCF [![Azure Pipelines](https://dev.azure.com/cncf/envoy/_apis/build/status/11?branchName=main)](https://dev.azure.com/cncf/envoy/_build/latest?definitionId=11&branchName=main) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/envoy.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:envoy) [![Jenkins](https://powerci.osuosl.org/buildStatus/icon?job=build-envoy-static-master&subject=ppc64le%20build)](https://powerci.osuosl.org/job/build-envoy-static-master/) +[![Jenkins](https://ibmz-ci.osuosl.org/buildStatus/icon?job=Envoy_IBMZ_CI&subject=s390x%20build)](https://ibmz-ci.osuosl.org/job/Envoy_IBMZ_CI/) ## Documentation * [Official documentation](https://www.envoyproxy.io/) * [FAQ](https://www.envoyproxy.io/docs/envoy/latest/faq/overview) * [Unofficial Chinese documentation](https://cloudnative.to/envoy/) +* [Example documentation](https://github.com/envoyproxy/examples/) * [Blog](https://medium.com/@mattklein123/envoy-threading-model-a8d44b922310) about the threading model * [Blog](https://medium.com/@mattklein123/envoy-hot-restart-1d16b14555b5) about hot restart * [Blog](https://medium.com/@mattklein123/envoy-stats-b65c7f363342) about stats architecture diff --git a/SECURITY.md b/SECURITY.md index 5a5233601a5f..a76fc0cc8aa6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -465,24 +465,20 @@ and security team to ensure they still qualify for inclusion on the list. | Organization | End User | Last Review | |:-------------:|:--------:|:-----------:| -| AWS | No | 06/21 | -| Cilium | No | 06/21 | -| Cloud Foundry | No | 06/21 | -| Datawire | No | 06/21 | -| F5 | No | 06/21 | -| Google | No | 06/21 | -| IBM | No | 06/21 | -| Istio | No | 06/21 | -| Microsoft | No | 2/21 | -| Red Hat | No | 06/21 | -| solo.io | No | 06/21 | -| Tetrate | No | 06/21 | -| VMware | No | 06/21 | -| Pinterest | Yes | 06/21 | -| Dropbox | Yes | 01/20 | -| Stripe | Yes | 01/20 | -| Square | Yes | 05/21 | -| Apple | Yes | 05/21 | -| Spotify | Yes | 06/21 | -| Netflix | Yes | 06/22 | +| AWS | No | 07/24 | +| Cilium | No | 07/24 | +| Cloud Foundry | No | 07/24 | +| F5 | No | 07/24 | +| Google | No | 07/24 | +| Istio | No | 07/24 | +| Microsoft | No | 07/24 | +| Red Hat | No | 07/24 | +| VMware | No | 07/24 | +| Tetrate | No | 07/24 | +| solo.io | No | 07/24 | +| Pinterest | Yes | 07/24 | +| Dropbox | Yes | 07/24 | +| Apple | Yes | 07/24 | +| Spotify | Yes | 02/21 | +| Netflix | Yes | 07/24 | | Slack | Yes | 07/24 | diff --git a/WORKSPACE b/WORKSPACE index 0f789feb23e5..9819ecb5ac1e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,6 +8,10 @@ load("//bazel:api_repositories.bzl", "envoy_api_dependencies") envoy_api_dependencies() +load("//bazel:repo.bzl", "envoy_repo") + +envoy_repo() + load("//bazel:repositories.bzl", "envoy_dependencies") envoy_dependencies() diff --git a/api/BUILD b/api/BUILD index 7a1db4f427aa..931fbea9c428 100644 --- a/api/BUILD +++ b/api/BUILD @@ -291,6 +291,7 @@ proto_library( "//envoy/extensions/matching/common_inputs/ssl/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/matching/input_matchers/ip/v3:pkg", + "//envoy/extensions/matching/input_matchers/metadata/v3:pkg", "//envoy/extensions/matching/input_matchers/runtime_fraction/v3:pkg", "//envoy/extensions/network/dns_resolver/apple/v3:pkg", "//envoy/extensions/network/dns_resolver/cares/v3:pkg", diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 59506e03b60a..6ca1e5d1fc7f 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -61,10 +61,6 @@ def api_dependencies(): external_http_archive( name = "com_github_chrusty_protoc_gen_jsonschema", ) - external_http_archive( - name = "rules_proto_grpc", - ) - external_http_archive( name = "envoy_toolshed", ) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 30769a65312a..53324145836a 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -175,17 +175,6 @@ REPOSITORY_LOCATIONS_SPEC = dict( use_category = ["api"], release_date = "2024-03-27", ), - rules_proto_grpc = dict( - project_name = "rules_proto_grpc", - project_desc = "Bazel rules for building Protobuf and gRPC code and libraries from proto_library targets ", - project_url = "https://github.com/rules-proto-grpc/rules_proto_grpc", - version = "4.6.0", - sha256 = "2a0860a336ae836b54671cbbe0710eec17c64ef70c4c5a88ccfd47ea6e3739bd", - strip_prefix = "rules_proto_grpc-{version}", - urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/{version}/rules_proto_grpc-{version}.tar.gz"], - use_category = ["build"], - release_date = "2023-12-14", - ), envoy_toolshed = dict( project_name = "envoy_toolshed", project_desc = "Tooling, libraries, runners and checkers for Envoy proxy's CI", diff --git a/api/envoy/config/cluster/v3/cluster.proto b/api/envoy/config/cluster/v3/cluster.proto index 5f347ade6d3d..ef6bbe121b4c 100644 --- a/api/envoy/config/cluster/v3/cluster.proto +++ b/api/envoy/config/cluster/v3/cluster.proto @@ -1154,6 +1154,8 @@ message Cluster { // [#not-implemented-hide:] // A list of metric names from ORCA load reports to propagate to LRS. // + // If not specified, then ORCA load reports will not be propagated to LRS. + // // For map fields in the ORCA proto, the string will be of the form ``.``. // For example, the string ``named_metrics.foo`` will mean to look for the key ``foo`` in the ORCA // ``named_metrics`` field. diff --git a/api/envoy/config/filter/http/ext_authz/v2/ext_authz.proto b/api/envoy/config/filter/http/ext_authz/v2/ext_authz.proto index c55938fc3cbe..c79dd4a24bc9 100644 --- a/api/envoy/config/filter/http/ext_authz/v2/ext_authz.proto +++ b/api/envoy/config/filter/http/ext_authz/v2/ext_authz.proto @@ -40,12 +40,11 @@ message ExtAuthz { // // 1. When set to true, the filter will *accept* client request even if the communication with // the authorization service has failed, or if the authorization service has returned a HTTP 5xx - // error. In case with GRPC authorization service, only PermissionDenied (7) and Unauthenticated (16) - // status codes will *reject* client requests. And other GRPC statuses will *accept* client requests. + // error. // // 2. When set to false, ext-authz will *reject* client requests and return a *Forbidden* // response if the communication with the authorization service has failed, or if the - // authorization service has returned a HTTP 5xx error or any non-Ok GRPC status. + // authorization service has returned a HTTP 5xx error. // // Note that errors can be *always* tracked in the :ref:`stats // `. diff --git a/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto b/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto index 357dd5fc645a..3b6a67cc9074 100644 --- a/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto +++ b/api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto @@ -57,12 +57,11 @@ message ExtAuthz { // // 1. When set to true, the filter will ``accept`` client request even if the communication with // the authorization service has failed, or if the authorization service has returned a HTTP 5xx - // error. In case with GRPC authorization service, only PermissionDenied (7) and Unauthenticated (16) - // status codes will ``reject`` client requests. And other GRPC statuses will ``accept`` client requests. + // error. // // 2. When set to false, ext-authz will ``reject`` client requests and return a ``Forbidden`` // response if the communication with the authorization service has failed, or if the - // authorization service has returned a HTTP 5xx error or any non-Ok GRPC status. + // authorization service has returned a HTTP 5xx error. // // Note that errors can be ``always`` tracked in the :ref:`stats // `. diff --git a/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto b/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto index aeaed7aa2ab7..1d79d39d99b8 100644 --- a/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto +++ b/api/envoy/extensions/filters/http/ext_proc/v3/ext_proc.proto @@ -5,6 +5,7 @@ package envoy.extensions.filters.http.ext_proc.v3; import "envoy/config/common/mutation_rules/v3/mutation_rules.proto"; import "envoy/config/core/v3/base.proto"; import "envoy/config/core/v3/grpc_service.proto"; +import "envoy/config/core/v3/http_service.proto"; import "envoy/extensions/filters/http/ext_proc/v3/processing_mode.proto"; import "envoy/type/matcher/v3/string.proto"; @@ -98,7 +99,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` object in a namespace matching the filter // name. // -// [#next-free-field: 20] +// [#next-free-field: 21] message ExternalProcessor { // Describes the route cache action to be taken when an external processor response // is received in response to request headers. @@ -125,7 +126,18 @@ message ExternalProcessor { // Configuration for the gRPC service that the filter will communicate with. // The filter supports both the "Envoy" and "Google" gRPC clients. - config.core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; + // Only one of ``grpc_service`` or ``http_service`` can be set. + // It is required that one of them must be set. + config.core.v3.GrpcService grpc_service = 1 + [(udpa.annotations.field_migrate).oneof_promotion = "ext_proc_service_type"]; + + // [#not-implemented-hide:] + // Configuration for the HTTP service that the filter will communicate with. + // Only one of ``http_service`` or + // :ref:`grpc_service `. + // can be set. It is required that one of them must be set. + ExtProcHttpService http_service = 20 + [(udpa.annotations.field_migrate).oneof_promotion = "ext_proc_service_type"]; // By default, if the gRPC stream cannot be established, or if it is closed // prematurely with an error, the filter will fail. Specifically, if the @@ -265,6 +277,12 @@ message ExternalProcessor { google.protobuf.Duration deferred_close_timeout = 19; } +// ExtProcHttpService is used for HTTP communication between the filter and the external processing service. +message ExtProcHttpService { + // Sets the HTTP service which the external processing requests must be sent to. + config.core.v3.HttpService http_service = 1; +} + // The MetadataOptions structure defines options for the sending and receiving of // dynamic metadata. Specifically, which namespaces to send to the server, whether // metadata returned by the server may be written, and how that metadata may be written. diff --git a/api/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto b/api/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto index 3684f994d65f..aae62145731a 100644 --- a/api/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto +++ b/api/envoy/extensions/filters/http/grpc_field_extraction/v3/config.proto @@ -52,7 +52,9 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // Here are config requirements // -// 1. the target field should be among the following primitive types: `string`, `uint32`, `uint64`, `int32`, `int64`, `sint32`, `sint64`, `fixed32`, `fixed64`, `sfixed32`, `sfixed64`, `float`, `double`. +// 1. the target field should be among the following primitive types: `string`, +// `uint32`, `uint64`, `int32`, `int64`, `sint32`, `sint64`, `fixed32`, +// `fixed64`, `sfixed32`, `sfixed64`, `float`, `double`, `map`. // // 2. the target field could be repeated. // @@ -61,9 +63,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Output Format // ------------- // -// 1. the extracted field names/values will be wrapped in be ``field`` -> ``values``, which will be added in the dynamic ``metadata``. +// 1. the extracted field names/values will be wrapped in be ``field`` -> ``values``, which will be added in the dynamic ``metadata``. // -// 2. if the field value is empty, a empty ```` will be set. +// 2. if the field value is empty, an empty ```` will be set. // // Performance // ----------- diff --git a/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto b/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto index 41d694a014dd..85f96eeef873 100644 --- a/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto +++ b/api/envoy/extensions/filters/http/jwt_authn/v3/config.proto @@ -355,11 +355,12 @@ message JwtProvider { // Specify the claim name you want to copy in which HTTP header. For examples, following config: // The claim must be of type; string, int, double, bool. Array type claims are not supported // - // .. code-block:: yaml - // - // claim_to_headers: - // - name: x-jwt-claim-nested-claim - // claim: claim.nested.key + // .. literalinclude:: /_configs/repo/jwt_authn.yaml + // :language: yaml + // :lines: 44-48 + // :linenos: + // :lineno-start: 44 + // :caption: :download:`jwt_authn.yaml ` // // This header is only reserved for jwt claim; any other value will be overwritten. repeated JwtClaimToHeader claim_to_headers = 15; diff --git a/api/envoy/extensions/filters/http/oauth2/v3/oauth.proto b/api/envoy/extensions/filters/http/oauth2/v3/oauth.proto index 703e3428b240..a1622b3631d1 100644 --- a/api/envoy/extensions/filters/http/oauth2/v3/oauth.proto +++ b/api/envoy/extensions/filters/http/oauth2/v3/oauth.proto @@ -24,6 +24,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#extension: envoy.filters.http.oauth2] // +// [#next-free-field: 6] message OAuth2Credentials { // [#next-free-field: 6] message CookieNames { @@ -70,6 +71,10 @@ message OAuth2Credentials { // The cookie names used in OAuth filters flow. CookieNames cookie_names = 4; + + // The domain to set the cookie on. If not set, the cookie will default to the host of the request, not including the subdomains. + // This is useful when token cookies need to be shared across multiple subdomains. + string cookie_domain = 5; } // OAuth config @@ -153,7 +158,7 @@ message OAuth2Config { // // If this value is not set, it will default to ``604800s``. In this case, the cookie with the refresh token will be expired // in a week. - // This setting is only considered if ``use_refresh_token`` is set to true, otherwise the authorization server expiration or ``defaul_expires_in`` is used. + // This setting is only considered if ``use_refresh_token`` is set to true, otherwise the authorization server expiration or ``default_expires_in`` is used. google.protobuf.Duration default_refresh_token_expires_in = 15; // If set to true, Envoy will not set a cookie for ID Token even if one is received from the Identity Provider. This may be useful in cases where the ID diff --git a/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto b/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto index f4d0c78597b2..712512ddb0b6 100644 --- a/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto +++ b/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto @@ -37,7 +37,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // HTTP connection manager :ref:`configuration overview `. // [#extension: envoy.filters.network.http_connection_manager] -// [#next-free-field: 58] +// [#next-free-field: 59] message HttpConnectionManager { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"; @@ -58,9 +58,8 @@ message HttpConnectionManager { // Prior knowledge is allowed). HTTP2 = 2; - // [#not-implemented-hide:] QUIC implementation is not production ready yet. Use this enum with - // caution to prevent accidental execution of QUIC code. I.e. `!= HTTP2` is no longer sufficient - // to distinguish HTTP1 and HTTP2 traffic. + // The connection manager will assume that the client is speaking HTTP/3. + // This needs to be consistent with listener and transport socket config. HTTP3 = 3; } @@ -447,6 +446,21 @@ message HttpConnectionManager { config.core.v3.HttpProtocolOptions common_http_protocol_options = 35 [(udpa.annotations.security).configure_for_untrusted_downstream = true]; + // If set to true, Envoy will not start a drain timer for downstream HTTP1 connections after + // :ref:`common_http_protocol_options.max_connection_duration + // ` passes. + // Instead, Envoy will wait for the next downstream request, add connection:close to the response + // headers, then close the connection after the stream ends. + // + // This behavior is compliant with `RFC 9112 section 9.6 `_ + // + // If set to false, ``max_connection_duration`` will cause Envoy to enter the normal drain + // sequence for HTTP1 with Envoy eventually closing the connection (once there are no active + // streams). + // + // Has no effect if ``max_connection_duration`` is unset. Defaults to false. + bool http1_safe_max_connection_duration = 58; + // Additional HTTP/1 settings that are passed to the HTTP/1 codec. // [#comment:TODO: The following fields are ignored when the // :ref:`header validation configuration ` @@ -459,7 +473,6 @@ message HttpConnectionManager { [(udpa.annotations.security).configure_for_untrusted_downstream = true]; // Additional HTTP/3 settings that are passed directly to the HTTP/3 codec. - // [#not-implemented-hide:] config.core.v3.Http3ProtocolOptions http3_protocol_options = 44; // An optional override that the connection manager will write to the server @@ -589,26 +602,33 @@ message HttpConnectionManager { // emitted by the connection manager. repeated config.accesslog.v3.AccessLog access_log = 13; + // The interval to flush the above access logs. + // // .. attention:: - // This field is deprecated in favor of - // :ref:`access_log_flush_interval - // `. - // Note that if both this field and :ref:`access_log_flush_interval - // ` - // are specified, the former (deprecated field) is ignored. + // + // This field is deprecated in favor of + // :ref:`access_log_flush_interval + // `. + // Note that if both this field and :ref:`access_log_flush_interval + // ` + // are specified, the former (deprecated field) is ignored. google.protobuf.Duration access_log_flush_interval = 54 [ deprecated = true, (validate.rules).duration = {gte {nanos: 1000000}}, (envoy.annotations.deprecated_at_minor_version) = "3.0" ]; + // If set to true, HCM will flush an access log once when a new HTTP request is received, after the request + // headers have been evaluated, and before iterating through the HTTP filter chain. + // // .. attention:: - // This field is deprecated in favor of - // :ref:`flush_access_log_on_new_request - // `. - // Note that if both this field and :ref:`flush_access_log_on_new_request - // ` - // are specified, the former (deprecated field) is ignored. + // + // This field is deprecated in favor of + // :ref:`flush_access_log_on_new_request + // `. + // Note that if both this field and :ref:`flush_access_log_on_new_request + // ` + // are specified, the former (deprecated field) is ignored. bool flush_access_log_on_new_request = 55 [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"]; diff --git a/api/envoy/extensions/filters/network/rbac/v3/rbac.proto b/api/envoy/extensions/filters/network/rbac/v3/rbac.proto index 823e18277d1f..9032a65924ea 100644 --- a/api/envoy/extensions/filters/network/rbac/v3/rbac.proto +++ b/api/envoy/extensions/filters/network/rbac/v3/rbac.proto @@ -4,6 +4,8 @@ package envoy.extensions.filters.network.rbac.v3; import "envoy/config/rbac/v3/rbac.proto"; +import "google/protobuf/duration.proto"; + import "xds/annotations/v3/status.proto"; import "xds/type/matcher/v3/matcher.proto"; @@ -26,7 +28,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // // Header should not be used in rules/shadow_rules in RBAC network filter as // this information is only available in :ref:`RBAC http filter `. -// [#next-free-field: 8] +// [#next-free-field: 9] message RBAC { option (udpa.annotations.versioning).previous_message_type = "envoy.config.filter.network.rbac.v2.RBAC"; @@ -87,4 +89,10 @@ message RBAC { // every payload (e.g., Mongo, MySQL, Kafka) set the enforcement type to // CONTINUOUS to enforce RBAC policies on every message boundary. EnforcementType enforcement_type = 4; + + // Delay the specified duration before closing the connection when the policy evaluation + // result is ``DENY``. If this is not present, the connection will be closed immediately. + // This is useful to provide a better protection for Envoy against clients that retries + // aggressively when the connection is rejected by the RBAC filter. + google.protobuf.Duration delay_deny = 8; } diff --git a/api/envoy/extensions/matching/common_inputs/network/v3/network_inputs.proto b/api/envoy/extensions/matching/common_inputs/network/v3/network_inputs.proto index 59756bc0c07b..bea415a7101f 100644 --- a/api/envoy/extensions/matching/common_inputs/network/v3/network_inputs.proto +++ b/api/envoy/extensions/matching/common_inputs/network/v3/network_inputs.proto @@ -103,3 +103,48 @@ message ApplicationProtocolInput { message FilterStateInput { string key = 1 [(validate.rules).string = {min_len: 1}]; } + +// Input that matches dynamic metadata by key. +// DynamicMetadataInput provides a general interface using ``filter`` and ``path`` to retrieve value from +// :ref:`Metadata `. +// +// For example, for the following Metadata: +// +// .. code-block:: yaml +// +// filter_metadata: +// envoy.xxx: +// prop: +// foo: bar +// xyz: +// hello: envoy +// +// The following DynamicMetadataInput will retrieve a string value "bar" from the Metadata. +// +// .. code-block:: yaml +// +// filter: envoy.xxx +// path: +// - key: prop +// - key: foo +// +// [#extension: envoy.matching.inputs.dynamic_metadata] +message DynamicMetadataInput { + // Specifies the segment in a path to retrieve value from Metadata. + // Note: Currently it's not supported to retrieve a value from a list in Metadata. This means that + // if the segment key refers to a list, it has to be the last segment in a path. + message PathSegment { + oneof segment { + option (validate.required) = true; + + // If specified, use the key to retrieve the value in a Struct. + string key = 1 [(validate.rules).string = {min_len: 1}]; + } + } + + // The filter name to retrieve the Struct from the Metadata. + string filter = 1 [(validate.rules).string = {min_len: 1}]; + + // The path to retrieve the Value from the Struct. + repeated PathSegment path = 2 [(validate.rules).repeated = {min_items: 1}]; +} diff --git a/api/envoy/extensions/matching/input_matchers/metadata/v3/BUILD b/api/envoy/extensions/matching/input_matchers/metadata/v3/BUILD new file mode 100644 index 000000000000..bfc486330911 --- /dev/null +++ b/api/envoy/extensions/matching/input_matchers/metadata/v3/BUILD @@ -0,0 +1,12 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/type/matcher/v3:pkg", + "@com_github_cncf_xds//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/matching/input_matchers/metadata/v3/metadata.proto b/api/envoy/extensions/matching/input_matchers/metadata/v3/metadata.proto new file mode 100644 index 000000000000..19d74fb41bf7 --- /dev/null +++ b/api/envoy/extensions/matching/input_matchers/metadata/v3/metadata.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.extensions.matching.input_matchers.metadata.v3; + +import "envoy/type/matcher/v3/value.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.matching.input_matchers.metadata.v3"; +option java_outer_classname = "MetadataProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/matching/input_matchers/metadata/v3;metadatav3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: metadata matcher] +// [#extension: envoy.matching.matchers.metadata_matcher] + +// Metadata matcher for metadata from http matching input data. +message Metadata { + // The Metadata is matched if the value retrieved by metadata matching input is matched to this value. + type.matcher.v3.ValueMatcher value = 1 [(validate.rules).message = {required: true}]; + + // If true, the match result will be inverted. + bool invert = 4; +} diff --git a/api/envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.proto b/api/envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.proto index 99c2e451047b..76b6bc9849e4 100644 --- a/api/envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.proto +++ b/api/envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.proto @@ -16,20 +16,31 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: Upstream HTTP/1.1 Proxy] // [#extension: envoy.transport_sockets.http_11_proxy] -// Configuration for HTTP/1.1 proxy transport sockets. -// This is intended for use in Envoy Mobile, though may eventually be extended -// for upstream Envoy use. -// If this transport socket is configured, and an intermediate filter adds the -// stream info necessary for proxying to the stream info (as the test filter -// does :repo:`here `) then +// The HTTP/1.1 proxy transport socket opens an upstream connection to a specified proxy address +// rather than the target host's address. If this transport socket is configured and proxy +// information is configured, then: // -// * Upstream connections will be directed to the specified proxy address rather -// than the host's address -// * Upstream TLS connections will have a raw HTTP/1.1 CONNECT header prefaced -// to the payload, and 200 response stripped (if less than 200 bytes) +// * Upstream connections to the proxy address will have a raw HTTP/1.1 CONNECT header prefaced to +// the payload, and 200 response stripped (if less than 200 bytes). // * Plaintext HTTP/1.1 connections will be sent with a fully qualified URL. // -// This transport socket is not compatible with HTTP/3, plaintext HTTP/2, or raw TCP. +// There are two primary ways to configure proxy information: +// +// * An intermediate filter adds the stream info necessary for proxying to the stream info (as the +// test filter does :repo:`here `). +// * Setting the "typed_filter_metadata" in :ref:`LbEndpoint.Metadata ` +// or :ref:`LocalityLbEndpoints.Metadata +// ` using the key +// "envoy.http11_proxy_transport_socket.proxy_address" and the proxy address in +// config::core::v3::Address format. +// +// Some important notes regarding this transport socket: +// +// * Configuration via stream info (as opposed to endpoint/locality metadata) will only proxy TLS +// connections to the proxy address on port 443. This is to maintain the original behavior of the +// transport socket when using this method of configuration. +// * The transport socket is not compatible with HTTP/3 or plaintext HTTP/2. +// message Http11ProxyUpstreamTransport { // The underlying transport socket being wrapped. config.core.v3.TransportSocket transport_socket = 1 [(validate.rules).message = {required: true}]; diff --git a/api/envoy/service/ratelimit/v3/rls.proto b/api/envoy/service/ratelimit/v3/rls.proto index 7375aceb5c2b..d69a323d88b7 100644 --- a/api/envoy/service/ratelimit/v3/rls.proto +++ b/api/envoy/service/ratelimit/v3/rls.proto @@ -49,6 +49,8 @@ message RateLimitRequest { // Rate limit requests can optionally specify the number of hits a request adds to the matched // limit. If the value is not set in the message, a request increases the matched limit by 1. + // This value can be overridden by setting filter state value ``envoy.ratelimit.hits_addend`` + // to the desired number. Invalid number (< 0) or number will be ignored. uint32 hits_addend = 3; } diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 96791470d5df..ea5e0db90006 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -230,6 +230,7 @@ proto_library( "//envoy/extensions/matching/common_inputs/ssl/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/matching/input_matchers/ip/v3:pkg", + "//envoy/extensions/matching/input_matchers/metadata/v3:pkg", "//envoy/extensions/matching/input_matchers/runtime_fraction/v3:pkg", "//envoy/extensions/network/dns_resolver/apple/v3:pkg", "//envoy/extensions/network/dns_resolver/cares/v3:pkg", diff --git a/bazel/dependency_imports.bzl b/bazel/dependency_imports.bzl index 1bf6c54a2588..6f782ef73263 100644 --- a/bazel/dependency_imports.bzl +++ b/bazel/dependency_imports.bzl @@ -18,7 +18,7 @@ load("@rules_rust//rust:defs.bzl", "rust_common") load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains", "rust_repository_set") # go version for rules_go -GO_VERSION = "1.20" +GO_VERSION = "1.22.5" JQ_VERSION = "1.7" YQ_VERSION = "4.24.4" diff --git a/bazel/external/boringssl_fips.genrule_cmd b/bazel/external/boringssl_fips.genrule_cmd index 7d18fdd3a2fc..51e6b72c7829 100755 --- a/bazel/external/boringssl_fips.genrule_cmd +++ b/bazel/external/boringssl_fips.genrule_cmd @@ -23,23 +23,23 @@ ROOT=./external/boringssl_fips pushd "$ROOT" export HOME="$PWD" -# Build tools requirements (from section 12.1 of https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4407.pdf): -# - Clang compiler version 12.0.0 (https://releases.llvm.org/download.html) -# - Go programming language version 1.16.5 (https://golang.org/dl/) +# Build tools requirements (from section 11 of https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4735.pdf): +# - Clang compiler version 14.0.0 (https://releases.llvm.org/download.html) +# - Go programming language version 1.18.1 (https://golang.org/dl/) # - Ninja build system version 1.10.2 (https://github.com/ninja-build/ninja/releases) -# - Cmake version 3.20.1 (https://cmake.org/download/) +# - Cmake version 3.22.1 (https://cmake.org/download/) # Override $PATH for build tools, to avoid picking up anything else. export PATH="/usr/bin:/bin" # Clang -VERSION=12.0.0 +VERSION=14.0.0 if [[ "$ARCH" == "x86_64" ]]; then - PLATFORM="x86_64-linux-gnu-ubuntu-20.04" - SHA256=a9ff205eb0b73ca7c86afc6432eed1c2d49133bd0d49e47b15be59bbf0dd292e + PLATFORM="x86_64-linux-gnu-ubuntu-18.04" + SHA256=61582215dafafb7b576ea30cc136be92c877ba1f1c31ddbbd372d6d65622fef5 else PLATFORM="aarch64-linux-gnu" - SHA256=d05f0b04fb248ce1e7a61fcd2087e6be8bc4b06b2cc348792f383abf414dec48 + SHA256=1792badcd44066c79148ffeb1746058422cc9d838462be07e3cb19a4b724a1ee fi curl -sLO https://github.com/llvm/llvm-project/releases/download/llvmorg-"$VERSION"/clang+llvm-"$VERSION"-"$PLATFORM".tar.xz @@ -55,13 +55,13 @@ if [[ `clang --version | head -1 | awk '{print $3}'` != "$VERSION" ]]; then fi # Go -VERSION=1.16.5 +VERSION=1.18.1 if [[ "$ARCH" == "x86_64" ]]; then PLATFORM="linux-amd64" - SHA256=b12c23023b68de22f74c0524f10b753e7b08b1504cb7e417eccebdd3fae49061 + SHA256=b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334 else PLATFORM="linux-arm64" - SHA256=d5446b46ef6f36fdffa852f73dfbbe78c1ddf010b99fa4964944b9ae8b4d6799 + SHA256=56a91851c97fb4697077abbca38860f735c32b38993ff79b088dac46e4735633 fi curl -sLO https://dl.google.com/go/go"$VERSION"."$PLATFORM".tar.gz \ @@ -95,13 +95,13 @@ fi cd .. # CMake -VERSION=3.20.1 +VERSION=3.22.1 if [[ "$ARCH" == "x86_64" ]]; then PLATFORM="linux-x86_64" - SHA256=b8c141bd7a6d335600ab0a8a35e75af79f95b837f736456b5532f4d717f20a09 + SHA256=73565c72355c6652e9db149249af36bcab44d9d478c5546fd926e69ad6b43640 else PLATFORM="linux-aarch64" - SHA256=5ad1f8139498a1956df369c401658ec787f63c8cb4e9759f2edaa51626a86512 + SHA256=601443375aa1a48a1a076bda7e3cca73af88400463e166fffc3e1da3ce03540b fi curl -sLO https://github.com/Kitware/CMake/releases/download/v"$VERSION"/cmake-"$VERSION"-"$PLATFORM".tar.gz \ @@ -124,6 +124,11 @@ cd boringssl # because the FIPS module itself is already built with -fPIC. mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. ninja + +# The `HostMatching` test contains hard-coded expired certificates and always fails due to the expiration. +# This should be removed during the next FIPS version upgrade, as the test code is fixed in later versions. +export GTEST_FILTER="-SSLTest.HostMatching" + ninja run_tests ./crypto/crypto_test diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index 0abec6540ec7..5f8bc42cfdb8 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -1373,7 +1373,6 @@ envoy_cc_library( name = "http2_core_headers_handler_interface_lib", hdrs = [ "quiche/http2/core/spdy_headers_handler_interface.h", - "quiche/spdy/core/spdy_headers_handler_interface.h", ], copts = quiche_copts, repository = "@envoy", @@ -3929,6 +3928,7 @@ envoy_quic_cc_library( ":quic_platform", ":quic_server_session_lib", ":quiche_common_callbacks", + ":quiche_common_intrusive_list_lib", ":quiche_common_text_utils_lib", ], ) diff --git a/bazel/foreign_cc/cares.patch b/bazel/foreign_cc/cares.patch deleted file mode 100644 index d666ef023f6e..000000000000 --- a/bazel/foreign_cc/cares.patch +++ /dev/null @@ -1,58 +0,0 @@ -From a070d7835d667b2fae5266fe1b790677dae47d25 Mon Sep 17 00:00:00 2001 -From: Brad House -Date: Thu, 12 Oct 2023 09:29:14 -0400 -Subject: [PATCH] Socket callbacks were passed SOCK_STREAM instead of - SOCK_DGRAM on udp - -A regression was introduced in 1.20.0 that would pass SOCK_STREAM on udp -connections due to code refactoring. If a client application validated this -data, it could cause issues as seen in gRPC. - -Fixes Issue: #571 -Fix By: Brad House (@bradh352) ---- - src/lib/ares_process.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/src/lib/ares_process.c b/src/lib/ares_process.c -index ca597db7ad..2f8e4de30d 100644 ---- a/src/lib/ares_process.c -+++ b/src/lib/ares_process.c -@@ -1065,6 +1065,7 @@ static ares_status_t open_socket(ares_channel channel, - unsigned short port; - struct server_connection *conn; - ares__llist_node_t *node; -+ int type = is_tcp?SOCK_STREAM:SOCK_DGRAM; - - if (is_tcp) { - port = aresx_sitous(server->addr.tcp_port? -@@ -1098,8 +1099,7 @@ static ares_status_t open_socket(ares_channel channel, - } - - /* Acquire a socket. */ -- s = ares__open_socket(channel, server->addr.family, -- is_tcp?SOCK_STREAM:SOCK_DGRAM, 0); -+ s = ares__open_socket(channel, server->addr.family, type, 0); - if (s == ARES_SOCKET_BAD) - return ARES_ECONNREFUSED; - -@@ -1129,8 +1129,7 @@ static ares_status_t open_socket(ares_channel channel, - #endif - - if (channel->sock_config_cb) { -- int err = channel->sock_config_cb(s, SOCK_STREAM, -- channel->sock_config_cb_data); -+ int err = channel->sock_config_cb(s, type, channel->sock_config_cb_data); - if (err < 0) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; -@@ -1148,8 +1147,7 @@ static ares_status_t open_socket(ares_channel channel, - } - - if (channel->sock_create_cb) { -- int err = channel->sock_create_cb(s, SOCK_STREAM, -- channel->sock_create_cb_data); -+ int err = channel->sock_create_cb(s, type, channel->sock_create_cb_data); - if (err < 0) { - ares__close_socket(channel, s); - return ARES_ECONNREFUSED; diff --git a/bazel/foreign_cc/curl.patch b/bazel/foreign_cc/curl.patch index 31d4b9b91c6c..708eb98d9dce 100644 --- a/bazel/foreign_cc/curl.patch +++ b/bazel/foreign_cc/curl.patch @@ -3,12 +3,12 @@ #Date: Tue Dec 22 15:31:03 2020 -0500 # # cmake: Add an option to disable libidn2 -# +# # New option USE_LIBIDN2 defaults to ON for libidn2 detection. Prior to # this change libidn2 detection could not be turned off in cmake builds. -# +# # Reported-by: William A Rowe Jr -# +# # Fixes https://github.com/curl/curl/issues/6361 # Closes #xxxx # @@ -17,47 +17,48 @@ #Date: Wed Oct 7 14:32:49 2020 -0500 # # Correct fragile windows assumptions -# +# # - Locking CMake to 3.16 breaks all features and corrections applied to # CMake 3.17 and later, including the correction of the poorly designed # and now abandoned Windows CRT election policy CMP0091 (see final para # of the policy description here: # https://cmake.org/cmake/help/v3.18/policy/CMP0091.html). Locking to # rev 3.16 from ensures a more difficult transition to CMake-current -# +# # - Windows curl builds previously only adjusted the Release and Debug # builds, and combined with CMP0091 to break other flavors. Update any # /MD* flags with /MT* present in the base and four alternate build # flavors, without introducing conflicting flag values or introducing # a CRT election where one is not present -# +# # - Windows clang-cl builds of curl static libs are broken when using # link-lld.exe because curl appended the dynamic run time flags to the # static library lib.exe options. While these were ignored/no-op on # Windows link.exe, they cause link-lld from LLVM/clang-cl compile # toolchain to fail to parse the library command. -# +# # Summary exists in this bazel-specific bug report; # https://github.com/bazelbuild/rules_foreign_cc/issues/426 diff --git a/CMakeLists.txt b/CMakeLists.txt -index ed60f07bc..0d2088cb9 100644 +index 580cc4357..13df6ca54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -62,6 +62,11 @@ - +@@ -44,6 +44,12 @@ + # variable is NOT DEFINED, the symbol detection will be performed. + cmake_minimum_required(VERSION 3.7...3.16 FATAL_ERROR) - ++ +# Revert CMake bug triggered by curl's defined max CMake policy version, see https://gitlab.kitware.com/cmake/cmake/-/issues/21288 +if(POLICY CMP0091) + cmake_policy(SET CMP0091 OLD) +endif() + + message(STATUS "Using CMake version ${CMAKE_VERSION}") + set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") - include(Utilities) - include(Macros) -@@ -306,9 +311,12 @@ if(ENABLE_MANUAL) +@@ -328,9 +334,12 @@ if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS) endif() - + if(CURL_STATIC_CRT) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") @@ -69,5 +70,5 @@ index ed60f07bc..0d2088cb9 100644 + endif() + endforeach() endif() - + # Disable warnings on Borland to avoid changing 3rd party code. diff --git a/bazel/repo.bzl b/bazel/repo.bzl new file mode 100644 index 000000000000..a2d909b3f99f --- /dev/null +++ b/bazel/repo.bzl @@ -0,0 +1,152 @@ +# `@envoy_repo` repository rule for managing the repo and querying its metadata. + +def _envoy_repo_impl(repository_ctx): + """This provides information about the Envoy repository + + You can access the current project and api versions and the path to the repository in + .bzl/BUILD files as follows: + + ```starlark + load("@envoy_repo//:version.bzl", "VERSION", "API_VERSION") + ``` + + `*VERSION` can be used to derive version-specific rules and can be passed + to the rules. + + The `VERSION`s and also the local `PATH` to the repo can be accessed in + python libraries/binaries. By adding `@envoy_repo` to `deps` they become + importable through the `envoy_repo` namespace. + + As the `PATH` is local to the machine, it is generally only useful for + jobs that will run locally. + + This can be useful, for example, for bazel run jobs to run bazel queries that cannot be run + within the constraints of a `genquery`, or that otherwise need access to the repository + files. + + Project and repo data can be accessed in JSON format using `@envoy_repo//:project`, eg: + + ```starlark + load("@aspect_bazel_lib//lib:jq.bzl", "jq") + + jq( + name = "project_version", + srcs = ["@envoy_repo//:data"], + out = "version.txt", + args = ["-r"], + filter = ".version", + ) + + ``` + + """ + repo_version_path = repository_ctx.path(repository_ctx.attr.envoy_version) + api_version_path = repository_ctx.path(repository_ctx.attr.envoy_api_version) + version = repository_ctx.read(repo_version_path).strip() + api_version = repository_ctx.read(api_version_path).strip() + repository_ctx.file("version.bzl", "VERSION = '%s'\nAPI_VERSION = '%s'" % (version, api_version)) + repository_ctx.file("path.bzl", "PATH = '%s'" % repo_version_path.dirname) + repository_ctx.file("__init__.py", "PATH = '%s'\nVERSION = '%s'\nAPI_VERSION = '%s'" % (repo_version_path.dirname, version, api_version)) + repository_ctx.file("WORKSPACE", "") + repository_ctx.file("BUILD", ''' +load("@rules_python//python:defs.bzl", "py_library") +load("@envoy//tools/base:envoy_python.bzl", "envoy_entry_point") +load("//:path.bzl", "PATH") + +py_library( + name = "envoy_repo", + srcs = ["__init__.py"], + visibility = ["//visibility:public"], +) + +envoy_entry_point( + name = "get_project_json", + pkg = "envoy.base.utils", + script = "envoy.project_data", + init_data = [":__init__.py"], +) + +genrule( + name = "project", + outs = ["project.json"], + cmd = """ + $(location :get_project_json) $$(dirname $(location @envoy//:VERSION.txt)) > $@ + """, + tools = [ + ":get_project_json", + "@envoy//:VERSION.txt", + "@envoy//changelogs", + ], + visibility = ["//visibility:public"], +) + +envoy_entry_point( + name = "release", + args = [ + "release", + PATH, + "--release-message-path=$(location @envoy//changelogs:summary)", + ], + data = ["@envoy//changelogs:summary"], + pkg = "envoy.base.utils", + script = "envoy.project", + init_data = [":__init__.py"], +) + +envoy_entry_point( + name = "dev", + args = [ + "dev", + PATH, + ], + pkg = "envoy.base.utils", + script = "envoy.project", + init_data = [":__init__.py"], +) + +envoy_entry_point( + name = "sync", + args = [ + "sync", + PATH, + ], + pkg = "envoy.base.utils", + script = "envoy.project", + init_data = [":__init__.py"], +) + +envoy_entry_point( + name = "publish", + args = [ + "publish", + PATH, + ], + pkg = "envoy.base.utils", + script = "envoy.project", + init_data = [":__init__.py"], +) + +envoy_entry_point( + name = "trigger", + args = [ + "trigger", + PATH, + ], + pkg = "envoy.base.utils", + script = "envoy.project", + init_data = [":__init__.py"], +) + +''') + +_envoy_repo = repository_rule( + implementation = _envoy_repo_impl, + attrs = { + "envoy_version": attr.label(default = "@envoy//:VERSION.txt"), + "envoy_api_version": attr.label(default = "@envoy//:API_VERSION.txt"), + }, +) + +def envoy_repo(): + if "envoy_repo" not in native.existing_rules().keys(): + _envoy_repo(name = "envoy_repo") diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index dc41c50433b8..ea147cf310bd 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -70,157 +70,6 @@ _default_envoy_build_config = repository_rule( }, ) -def _envoy_repo_impl(repository_ctx): - """This provides information about the Envoy repository - - You can access the current project and api versions and the path to the repository in - .bzl/BUILD files as follows: - - ```starlark - load("@envoy_repo//:version.bzl", "VERSION", "API_VERSION") - ``` - - `*VERSION` can be used to derive version-specific rules and can be passed - to the rules. - - The `VERSION`s and also the local `PATH` to the repo can be accessed in - python libraries/binaries. By adding `@envoy_repo` to `deps` they become - importable through the `envoy_repo` namespace. - - As the `PATH` is local to the machine, it is generally only useful for - jobs that will run locally. - - This can be useful, for example, for bazel run jobs to run bazel queries that cannot be run - within the constraints of a `genquery`, or that otherwise need access to the repository - files. - - Project and repo data can be accessed in JSON format using `@envoy_repo//:project`, eg: - - ```starlark - load("@aspect_bazel_lib//lib:jq.bzl", "jq") - - jq( - name = "project_version", - srcs = ["@envoy_repo//:data"], - out = "version.txt", - args = ["-r"], - filter = ".version", - ) - - ``` - - """ - repo_version_path = repository_ctx.path(repository_ctx.attr.envoy_version) - api_version_path = repository_ctx.path(repository_ctx.attr.envoy_api_version) - version = repository_ctx.read(repo_version_path).strip() - api_version = repository_ctx.read(api_version_path).strip() - repository_ctx.file("version.bzl", "VERSION = '%s'\nAPI_VERSION = '%s'" % (version, api_version)) - repository_ctx.file("path.bzl", "PATH = '%s'" % repo_version_path.dirname) - repository_ctx.file("__init__.py", "PATH = '%s'\nVERSION = '%s'\nAPI_VERSION = '%s'" % (repo_version_path.dirname, version, api_version)) - repository_ctx.file("WORKSPACE", "") - repository_ctx.file("BUILD", ''' -load("@rules_python//python:defs.bzl", "py_library") -load("@envoy//tools/base:envoy_python.bzl", "envoy_entry_point") -load("//:path.bzl", "PATH") - -py_library( - name = "envoy_repo", - srcs = ["__init__.py"], - visibility = ["//visibility:public"], -) - -envoy_entry_point( - name = "get_project_json", - pkg = "envoy.base.utils", - script = "envoy.project_data", - init_data = [":__init__.py"], -) - -genrule( - name = "project", - outs = ["project.json"], - cmd = """ - $(location :get_project_json) $$(dirname $(location @envoy//:VERSION.txt)) > $@ - """, - tools = [ - ":get_project_json", - "@envoy//:VERSION.txt", - "@envoy//changelogs", - ], - visibility = ["//visibility:public"], -) - -envoy_entry_point( - name = "release", - args = [ - "release", - PATH, - "--release-message-path=$(location @envoy//changelogs:summary)", - ], - data = ["@envoy//changelogs:summary"], - pkg = "envoy.base.utils", - script = "envoy.project", - init_data = [":__init__.py"], -) - -envoy_entry_point( - name = "dev", - args = [ - "dev", - PATH, - ], - pkg = "envoy.base.utils", - script = "envoy.project", - init_data = [":__init__.py"], -) - -envoy_entry_point( - name = "sync", - args = [ - "sync", - PATH, - ], - pkg = "envoy.base.utils", - script = "envoy.project", - init_data = [":__init__.py"], -) - -envoy_entry_point( - name = "publish", - args = [ - "publish", - PATH, - ], - pkg = "envoy.base.utils", - script = "envoy.project", - init_data = [":__init__.py"], -) - -envoy_entry_point( - name = "trigger", - args = [ - "trigger", - PATH, - ], - pkg = "envoy.base.utils", - script = "envoy.project", - init_data = [":__init__.py"], -) - -''') - -_envoy_repo = repository_rule( - implementation = _envoy_repo_impl, - attrs = { - "envoy_version": attr.label(default = "@envoy//:VERSION.txt"), - "envoy_api_version": attr.label(default = "@envoy//:API_VERSION.txt"), - }, -) - -def envoy_repo(): - if "envoy_repo" not in native.existing_rules().keys(): - _envoy_repo(name = "envoy_repo") - # Bazel native C++ dependencies. For the dependencies that doesn't provide autoconf/automake builds. def _cc_deps(): external_http_archive("grpc_httpjson_transcoding") @@ -230,6 +79,7 @@ def _cc_deps(): patches = ["@envoy//bazel:com_google_protoconverter.patch"], ) external_http_archive("com_google_protofieldextraction") + external_http_archive("com_google_protoprocessinglib") external_http_archive("ocp") native.bind( name = "path_matcher", @@ -254,9 +104,6 @@ def _rust_deps(): ) def envoy_dependencies(skip_targets = []): - # Add a binding for repository variables. - envoy_repo() - # Setup Envoy developer tools. envoy_dev_binding() @@ -302,7 +149,7 @@ def envoy_dependencies(skip_targets = []): _com_github_google_tcmalloc() _com_github_gperftools_gperftools() _com_github_grpc_grpc() - _com_github_rules_proto_grpc() + _rules_proto_grpc() _com_github_unicode_org_icu() _com_github_intel_ipp_crypto_crypto_mb() _com_github_intel_ipp_crypto_crypto_mb_fips() @@ -361,6 +208,8 @@ def envoy_dependencies(skip_targets = []): external_http_archive("bazel_toolchains") external_http_archive("bazel_compdb") external_http_archive("envoy_build_tools") + external_http_archive(name = "envoy_examples") + _com_github_maxmind_libmaxminddb() external_http_archive("rules_pkg") @@ -443,11 +292,6 @@ def _com_github_c_ares_c_ares(): external_http_archive( name = "com_github_c_ares_c_ares", build_file_content = BUILD_ALL_CONTENT, - # Patch c-ares library aith commit - # https://github.com/c-ares/c-ares/commit/a070d7835d667b2fae5266fe1b790677dae47d25 - # This commit fixes an issue when the gRPC library attempts to resolve a domain name. - patches = ["@envoy//bazel/foreign_cc:cares.patch"], - patch_args = ["-p1"], ) native.bind( name = "ares", @@ -1222,8 +1066,8 @@ def _com_github_grpc_grpc(): actual = "@com_github_grpc_grpc//test/core/tsi/alts/fake_handshaker:transport_security_common_proto", ) -def _com_github_rules_proto_grpc(): - external_http_archive("com_github_rules_proto_grpc") +def _rules_proto_grpc(): + external_http_archive("rules_proto_grpc") def _re2(): external_http_archive("com_googlesource_code_re2") diff --git a/bazel/repositories_extra.bzl b/bazel/repositories_extra.bzl index 6bdfe928ccb9..9414073fc7fd 100644 --- a/bazel/repositories_extra.bzl +++ b/bazel/repositories_extra.bzl @@ -1,6 +1,5 @@ load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies") load("@bazel_features//:deps.bzl", "bazel_features_deps") -load("@com_github_rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains") load("@emsdk//:deps.bzl", emsdk_deps = "deps") load("@proxy_wasm_cpp_host//bazel/cargo/wasmtime:crates.bzl", "wasmtime_fetch_remote_crates") load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") @@ -21,7 +20,6 @@ def envoy_dependencies_extra( emsdk_deps() raze_fetch_remote_crates() wasmtime_fetch_remote_crates() - rules_proto_grpc_toolchains() py_repositories() # Registers underscored Python minor version - eg `python3_10` diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 3532cc706ce4..e7c3127c2b77 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -92,6 +92,20 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/bazelbuild/buildtools/archive/v{version}.tar.gz"], use_category = ["test_only"], ), + envoy_examples = dict( + project_name = "envoy_examples", + project_desc = "Envoy proxy examples", + project_url = "https://github.com/envoyproxy/examples", + version = "0.0.2", + sha256 = "c19d5542eb1b105c60a13170c7cdc8f15b489ae06d49374962ea131a50c13c49", + strip_prefix = "examples-{version}", + urls = ["https://github.com/envoyproxy/examples/archive/v{version}.tar.gz"], + use_category = ["test_only"], + release_date = "2024-08-07", + cpe = "N/A", + license = "Apache-2.0", + license_url = "https://github.com/envoyproxy/examples/blob/v{version}/LICENSE", + ), rules_fuzzing = dict( project_name = "Fuzzing Rules for Bazel", project_desc = "Bazel rules for fuzz tests", @@ -149,11 +163,17 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_url = "https://boringssl.googlesource.com/boringssl/+/master/crypto/fipsmodule/FIPS.md", # When this is updated to a revision newer than 2022-08-12, # CertValidatorUtil::setIgnoreCertificateExpiration can be simplified. - version = "fips-20210429", - sha256 = "a4d069ccef6f3c7bc0c68de82b91414f05cb817494cd1ab483dcf3368883c7c2", - urls = ["https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-853ca1ea1168dff08011e5d42d94609cc0ca2e27.tar.xz"], + # + # !!! NOTE !!! + # Anytime the FIPS BoringSSL version is upgraded, `bazel/external/boringssl_fips.genrule_cmd` must be updated to use the toolchain + # specified in the associated accredidation certificate, which can be found linked from + # https://boringssl.googlesource.com/boringssl/+/refs/heads/master/crypto/fipsmodule/FIPS.md, for example + # https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4735. + version = "fips-20220613", + sha256 = "62f733289f2d677c2723f556aa58034c438f3a7bbca6c12b156538a88e38da8a", + urls = ["https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-0c6f40132b828e92ba365c6b7680e32820c63fa7.tar.xz"], use_category = ["controlplane", "dataplane_core"], - release_date = "2021-04-29", + release_date = "2022-06-13", cpe = "cpe:2.3:a:google:boringssl:*", ), aspect_bazel_lib = dict( @@ -230,12 +250,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "c-ares", project_desc = "C library for asynchronous DNS requests", project_url = "https://c-ares.haxx.se/", - version = "1.20.1", - sha256 = "de24a314844cb157909730828560628704f4f896d167dd7da0fa2fb93ea18b10", + version = "1.21.0", + sha256 = "cd7aa3af1d3ee780d6437039a7ddb7f1ec029f9c4f7aabb0197e384eb5bc2f2d", strip_prefix = "c-ares-{version}", urls = ["https://github.com/c-ares/c-ares/releases/download/cares-{underscore_version}/c-ares-{version}.tar.gz"], use_category = ["dataplane_core", "controlplane"], - release_date = "2023-10-08", + release_date = "2023-10-27", cpe = "cpe:2.3:a:c-ares_project:c-ares:*", license = "c-ares", license_url = "https://github.com/c-ares/c-ares/blob/cares-{underscore_version}/LICENSE.md", @@ -398,7 +418,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( license = "Apache-2.0", license_url = "https://github.com/grpc/grpc/blob/v{version}/LICENSE", ), - com_github_rules_proto_grpc = dict( + rules_proto_grpc = dict( project_name = "Protobuf and gRPC rules for Bazel", project_desc = "Bazel rules for building Protobuf and gRPC code and libraries from proto_library targets", project_url = "https://github.com/rules-proto-grpc/rules_proto_grpc", @@ -956,13 +976,13 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "proto-converter", project_desc = "Library that supports the conversion between protobuf binary and json", project_url = "https://github.com/grpc-ecosystem/proto-converter", - version = "d77ff301f48bf2e7a0f8935315e847c1a8e00017", - sha256 = "6081836fa3838ebb1aa15089a5c3e20f877a0244c7a39b92a2000efb40408dcb", + version = "1db76535b86b80aa97489a1edcc7009e18b67ab7", + sha256 = "9555d9cf7bd541ea5fdb67d7d6b72ea44da77df3e27b960b4155dc0c6b81d476", strip_prefix = "proto-converter-{version}", urls = ["https://github.com/grpc-ecosystem/proto-converter/archive/{version}.zip"], use_category = ["dataplane_ext"], extensions = ["envoy.filters.http.grpc_json_transcoder", "envoy.filters.http.grpc_field_extraction"], - release_date = "2023-06-07", + release_date = "2024-06-25", cpe = "N/A", license = "Apache-2.0", license_url = "https://github.com/grpc-ecosystem/proto-converter/blob/{version}/LICENSE", @@ -971,17 +991,32 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "proto-field-extraction", project_desc = "Library that supports the extraction from protobuf binary", project_url = "https://github.com/grpc-ecosystem/proto-field-extraction", - version = "2dfe27548e1f21a665f9068b97b2fc5beb678566", - sha256 = "ddbbd0dd07012339ac467f5fdac5c294e1efcdc93bb4b7152d468ddbfc9772f0", + version = "d5d39f0373e9b6691c32c85929838b1006bcb3fb", + sha256 = "cba864db90806515afa553aaa2fb3683df2859a7535e53a32cb9619da9cebc59", strip_prefix = "proto-field-extraction-{version}", urls = ["https://github.com/grpc-ecosystem/proto-field-extraction/archive/{version}.zip"], use_category = ["dataplane_ext"], extensions = ["envoy.filters.http.grpc_json_transcoder", "envoy.filters.http.grpc_field_extraction"], - release_date = "2023-07-18", + release_date = "2024-07-10", cpe = "N/A", license = "Apache-2.0", license_url = "https://github.com/grpc-ecosystem/proto-field-extraction/blob/{version}/LICENSE", ), + com_google_protoprocessinglib = dict( + project_name = "proto_processing_lib", + project_desc = "Library that provides utility functionality for proto field scrubbing", + project_url = "https://github.com/grpc-ecosystem/proto_processing_lib", + version = "43bd06909a4ccfa5788dc8bf850e40102166e63f", + sha256 = "8f99bd6f568c6fddcba1ed51290eaa5556a0ad374524ba6f532c6c828a73214b", + strip_prefix = "proto_processing_lib-{version}", + urls = ["https://github.com/grpc-ecosystem/proto_processing_lib/archive/{version}.zip"], + use_category = ["dataplane_ext"], + extensions = ["envoy.filters.http.grpc_json_transcoder", "envoy.filters.http.grpc_field_extraction"], + release_date = "2024-08-06", + cpe = "N/A", + license = "Apache-2.0", + license_url = "https://github.com/grpc-ecosystem/proto_processing_lib/blob/{version}/LICENSE", + ), ocp = dict( project_name = "ocp", project_desc = "Libraries used in gRPC field extraction library", @@ -1136,8 +1171,8 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "curl", project_desc = "Library for transferring data with URLs", project_url = "https://curl.haxx.se", - version = "8.4.0", - sha256 = "816e41809c043ff285e8c0f06a75a1fa250211bbfb2dc0a037eeef39f1a9e427", + version = "8.9.1", + sha256 = "291124a007ee5111997825940b3876b3048f7d31e73e9caa681b80fe48b2dcd5", strip_prefix = "curl-{version}", urls = ["https://github.com/curl/curl/releases/download/curl-{underscore_version}/curl-{version}.tar.gz"], use_category = ["dataplane_ext", "observability_ext"], @@ -1147,7 +1182,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( "envoy.grpc_credentials.aws_iam", "envoy.tracers.opencensus", ], - release_date = "2023-10-11", + release_date = "2024-07-31", cpe = "cpe:2.3:a:haxx:libcurl:*", license = "curl", license_url = "https://github.com/curl/curl/blob/curl-{underscore_version}/COPYING", @@ -1186,12 +1221,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( project_name = "QUICHE", project_desc = "QUICHE (QUIC, HTTP/2, Etc) is Google‘s implementation of QUIC and related protocols", project_url = "https://github.com/google/quiche", - version = "f4ed5e0c74485fb302367b833b8974373fed9e4c", - sha256 = "05e40b18e78b76a14bfa02eca1d6ebcf4c2ea0333c5db9fbe04287f912db2c20", + version = "36723962ef5c9f3f9f42093ff9cbe057bc7a80c4", + sha256 = "8735afd08104215a8487cc9f2ffff1adc16e6168dc61c4e65127a3fb23d90c54", urls = ["https://github.com/google/quiche/archive/{version}.tar.gz"], strip_prefix = "quiche-{version}", use_category = ["controlplane", "dataplane_core"], - release_date = "2024-07-26", + release_date = "2024-08-11", cpe = "N/A", license = "BSD-3-Clause", license_url = "https://github.com/google/quiche/blob/{version}/LICENSE", diff --git a/changelogs/current.yaml b/changelogs/current.yaml index 7a0ac131d20b..43b611011d06 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -6,17 +6,66 @@ behavior_changes: change: | Removed support for (long deprecated) opentracing. See `issue 27401 `_ for details. +- area: golang + change: | + Change ``OnLogDownstreamStart``, ``OnLogDownstreamPeriodic`` and ``OnLog`` methods so that user can get the request/response's + headers and trailers when producing access log. +- area: http + change: | + Added HTTP1-safe option for :ref:`max_connection_duration + ` in + HttpConnectionManager. When enabled, ``max_connection_duration`` will only drain downstream + HTTP1 connections by adding the Connection:close response header; it will never cause the + HttpConnectionManager to close the connection itself. Defaults to off ("unsafe" -- check + \#34356) and is configurable via :ref:`http1_safe_max_connection_duration + `. +- area: eds + change: | + Enabling caching caching of EDS assignments when used with ADS by default (introduced in Envoy v1.28). + Prior to this change, Envoy required that EDS assignments were sent after an EDS cluster was updated. + If no EDS assignment was received for the cluster, it ended up with an empty assignment. + Following this change, after a cluster update, Envoy waits for an EDS assignment until + :ref:`initial_fetch_timeout ` times out, and will then apply + the cached assignment and finish updating the warmed cluster. This change temporarily disabled by setting + the runtime flag ``envoy.restart_features.use_eds_cache_for_ads`` to ``false``. +- area: stats scoped_rds + change: | + Added new tag extraction so that scoped rds stats have their :ref:'scope_route_config_name + ' and stat prefix extracted. minor_behavior_changes: # *Changes that may cause incompatibilities for some users, but should not for most* +- area: command line options + change: | + :option:`--enable-fine-grain-logging` and :option:`--component-log-level` were incompatible in that one + would make the other ineffective. Setting both options at once is now an error, to reduce potential confusion. - area: tcp change: | Added support for :ref:`connection_pool_per_downstream_connection ` flag in tcp connection pool. +- area: http3 + change: | + The ACCEPT_UNTRUSTED option now works more consistently for HTTP/3 requests. This change is + guarded by ``envoy.reloadable_features.extend_h3_accept_untrusted``. +- area: http3 + change: | + HTTP/3 alt-svc headers will now be respected from IP-address-based hostnames. This change is + guarded by runtime guard ``envoy.reloadable_features.allow_alt_svc_for_ips``. - area: lua change: | When Lua script executes httpCall, backpressure is exercised when receiving body from downstream client. This behavior can be reverted by setting the runtime guard ``envoy.reloadable_features.lua_flow_control_while_http_call`` to false. +- area: http + change: | + Modified the authority header value validator to allow the same characters as oghttp2 + plus the "@" character. This is compliant with nghttp2, and supports the HTTP/1 use-cases + that allow user-info@ as part of the authority. This behavior can be reverted by setting + the runtime guard ``envoy.reloadable_features.internal_authority_header_validator`` to false. +- area: sni + change: | + When computing SNI and SAN value for the auto-sni and auto-san verification feature, + route host manipulations are now taken into account. This behavior can be reverted + by setting the runtime guard ``envoy_reloadable_features_use_route_host_mutation_for_auto_sni_san`` to false. bug_fixes: # *Changes expected to improve the state of the world and are unlikely to have negative effects* @@ -29,12 +78,6 @@ bug_fixes: - area: c-ares change: | Applying a C-ares patch to fix DNS resoultion by the Google gRPC library. -- area: ext_authz - change: | - Fixed fail-open behavior of the :ref:`failure_mode_allow config option - ` - when a grpc external authz server is used. - The behavior can be enabled by ``envoy_reloadable_features_process_ext_authz_grpc_error_codes_as_errors``. - area: websocket change: | Fixed a bug where the websocket upgrade filter would not take into account per-filter configs. @@ -42,6 +85,10 @@ bug_fixes: change: | Add runtime guard for timeout error code 504 Gateway Timeout that is returned to downstream. If runtime flag ``envoy.reloadable_features.ext_proc_timeout_error`` is set to false, old error code 500 Internal Server Error will be returned. +- area: rbac + change: | + RBAC will now allow stat prefixes configured in per-route config to override the base config's + stat prefix. removed_config_or_runtime: # *Normally occurs at the end of the* :ref:`deprecation period ` @@ -69,6 +116,10 @@ removed_config_or_runtime: change: | Removed runtime flag ``envoy.reloadable_features.abort_filter_chain_on_stream_reset`` and legacy code path. +- area: http + change: | + Removed runtime flag ``envoy.reloadable_features.http1_connection_close_header_in_redirect`` and + legacy code paths. - area: grpc reverse bridge change: | Removed ``envoy.reloadable_features.grpc_http1_reverse_bridge_handle_empty_response`` runtime @@ -80,12 +131,30 @@ removed_config_or_runtime: - area: stateful_session change: | Removed ``envoy.reloadable_features.stateful_session_encode_ttl_in_cookie`` runtime flag and legacy code paths. +- area: quic + change: | + Removed ``envoy.reloadable_features.quic_fix_filter_manager_uaf`` runtime flag and legacy code paths. +- area: udp + change: | + Removed ``envoy.restart_features.udp_read_normalize_addresses`` runtime flag and legacy code paths. +- area: upstream + change: | + Removed runtime flag ``envoy.reloadable_features.upstream_allow_connect_with_2xx`` and legacy code paths. - area: upstream flow control change: | Removed ``envoy.reloadable_features.upstream_wait_for_response_headers_before_disabling_read`` runtime flag and legacy code paths. +- area: dynamic forward proxy + change: | + Removed ``envoy.reloadable_features.normalize_host_for_preresolve_dfp_dns`` runtime flag and legacy code paths. new_features: +- area: redis + change: | + Added support for publish. +- area: jwt_authn + change: | + Added missing implementation to jwt_authn matchers to allow glob pattern matching. - area: tls change: | Added :ref:`prefer_client_ciphers @@ -100,6 +169,13 @@ new_features: change: | added %UPSTREAM_CLUSTER_RAW% access log formatter to log the original upstream cluster name, regardless of whether ``alt_stat_name`` is set. +- area: formatter + change: | + Added full feature absl::FormatTime() support to the DateFormatter. This allows the timepoint formatters (like + ``%START_TIME%``) to use ``%E#S``, ``%E*S``, ``%E#f`` and ``%E*f`` to format the subsecond part of the timepoint. +- area: http_11_proxy + change: | + Added the option to configure the transport socket via locality or endpoint metadata. - area: sockets change: | Added socket ``type`` field for specifying a socket type to apply the socket option to under :ref:`SocketOption @@ -111,9 +187,45 @@ new_features: ` to allow overriding TLS certificate selection behavior. An extension can select certificate base on the incoming SNI, in both sync and async mode. +- area: oauth + change: | + Added :ref:`cookie_domain ` + field to OAuth2 filter to allow setting the domain of cookies. +- area: access log + change: | + Added support for :ref:`%DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1% `, + ``%DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256``, and ``%DOWNSTREAM_PEER_CHAIN_SERIALS%``, as access log formatters. +- area: matching + change: | + Added dynamic metadata matcher support :ref:`Dynamic metadata input ` + and :ref:`Dynamic metadata input matcher `. +- area: ratelimit + change: | + Added the ability to modify :ref:`hits_addend ` + by setting by setting filter state value ``envoy.ratelimit.hits_addend`` to the desired value. - area: access_log change: | Added new access log command operators ``%START_TIME_LOCAL%`` and ``%EMIT_TIME_LOCAL%``, similar to ``%START_TIME%`` and ``%EMIT_TIME%``, but use local time zone. +- area: dns + change: | + Prefer using IPv6 address when addresses from both families are available. + Can be reverted by setting ``envoy.reloadable_features.prefer_ipv6_dns_on_macos`` to false. +- area: grpc_field_extraction + change: | + Added ``map`` support: Target fields of type ``map`` can be extracted and added to dynamic metadata. +- area: rbac + change: | + Added :ref:`delay_deny ` to support deny connection after + the configured duration. +- area: http3 + change: | + ``http3_protocol_options`` in ``HttpConnectionManager`` has been upgraded to general access. +- area: cluster + change: | + Customizing the happy eyeballs algorithm for an upstream cluster by configuring + :ref:`happy_eyeballs_config `. + A default configuration will be used if not provided. This behavior can be reverted + by setting the runtime guard ``envoy.reloadable_features.use_config_in_happy_eyeballs`` to false. deprecated: diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 8b634a2048fa..038a7c7e4c06 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -55,6 +55,8 @@ FETCH_PROTO_TARGETS=( @com_github_bufbuild_buf//:bin/buf //tools/proto_format/...) +GCS_REDIRECT_PATH="${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER:-${BUILD_SOURCEBRANCHNAME}}" + retry () { local n wait iterations wait="${1}" @@ -233,16 +235,6 @@ function bazel_contrib_binary_build() { bazel_binary_build "$1" "${ENVOY_CONTRIB_BUILD_TARGET}" "${ENVOY_CONTRIB_BUILD_DEBUG_INFORMATION}" envoy-contrib } -function run_ci_verify () { - export DOCKER_NO_PULL=1 - export DOCKER_RMI_CLEANUP=1 - # This is set to simulate an environment where users have shared home drives protected - # by a strong umask (ie only group readable by default). - umask 027 - chmod -R o-rwx examples/ - "${ENVOY_SRCDIR}/ci/verify_examples.sh" "${@}" -} - CI_TARGET=$1 shift @@ -258,7 +250,7 @@ if [[ $# -ge 1 ]]; then else # Coverage test will add QUICHE tests by itself. COVERAGE_TEST_TARGETS=("//test/...") - if [[ "${CI_TARGET}" == "release" ]]; then + if [[ "${CI_TARGET}" == "release" || "${CI_TARGET}" == "release.test_only" ]]; then # We test contrib on release only. COVERAGE_TEST_TARGETS=("${COVERAGE_TEST_TARGETS[@]}" "//contrib/...") elif [[ "${CI_TARGET}" == "msan" ]]; then @@ -491,7 +483,16 @@ case $CI_TARGET in else TARGET=coverage fi - "${ENVOY_SRCDIR}/ci/upload_gcs_artifact.sh" "/source/generated/${TARGET}" "$TARGET" + GCS_LOCATION=$( + bazel run //tools/gcs:upload \ + "${GCS_ARTIFACT_BUCKET}" \ + "${GCP_SERVICE_ACCOUNT_KEY_PATH}" \ + "/source/generated/${TARGET}" \ + "$TARGET" \ + "${GCS_REDIRECT_PATH}") + if [[ "${COVERAGE_FAILED}" -eq 1 ]]; then + echo "##vso[task.logissue type=error]Coverage failed, check artifact at: ${GCS_LOCATION}" + fi ;; debug) @@ -652,7 +653,12 @@ case $CI_TARGET in docker-upload) setup_clang_toolchain - "${ENVOY_SRCDIR}/ci/upload_gcs_artifact.sh" "${BUILD_DIR}/build_images" docker + bazel run //tools/gcs:upload \ + "${GCS_ARTIFACT_BUCKET}" \ + "${GCP_SERVICE_ACCOUNT_KEY_PATH}" \ + "${BUILD_DIR}/build_images" \ + "docker" \ + "${GCS_REDIRECT_PATH}" ;; dockerhub-publish) @@ -694,7 +700,12 @@ case $CI_TARGET in docs-upload) setup_clang_toolchain - "${ENVOY_SRCDIR}/ci/upload_gcs_artifact.sh" /source/generated/docs docs + bazel run //tools/gcs:upload \ + "${GCS_ARTIFACT_BUCKET}" \ + "${GCP_SERVICE_ACCOUNT_KEY_PATH}" \ + /source/generated/docs \ + docs \ + "${GCS_REDIRECT_PATH}" ;; fetch|fetch-*) @@ -714,11 +725,15 @@ case $CI_TARGET in fetch-gcc) targets=("${FETCH_GCC_TARGETS[@]}") ;; - fetch-release) + fetch-release|fetch-release.test_only) targets=( "${FETCH_BUILD_TARGETS[@]}" "${FETCH_ALL_TEST_TARGETS[@]}") ;; + fetch-release.server_only) + targets=( + "${FETCH_BUILD_TARGETS[@]}") + ;; fetch-*coverage) targets=("${FETCH_TEST_TARGETS[@]}") ;; @@ -828,8 +843,8 @@ case $CI_TARGET in "${PUBLISH_ARGS[@]}" ;; - release|release.server_only) - if [[ "$CI_TARGET" == "release" ]]; then + release|release.server_only|release.test_only) + if [[ "$CI_TARGET" == "release" || "$CI_TARGET" == "release.test_only" ]]; then # When testing memory consumption, we want to test against exact byte-counts # where possible. As these differ between platforms and compile options, we # define the 'release' builds as canonical and test them only in CI, so the @@ -841,19 +856,13 @@ case $CI_TARGET in fi fi setup_clang_toolchain - ENVOY_BINARY_DIR="${ENVOY_BUILD_DIR}/bin" - if [[ -e "${ENVOY_BINARY_DIR}" ]]; then - echo "Existing output directory found (${ENVOY_BINARY_DIR}), removing ..." - rm -rf "${ENVOY_BINARY_DIR}" - fi - mkdir -p "$ENVOY_BINARY_DIR" # As the binary build package enforces compiler options, adding here to ensure the tests and distribution build # reuse settings and any already compiled artefacts, the bundle itself will always be compiled # `--stripopt=--strip-all -c opt` BAZEL_RELEASE_OPTIONS=( --stripopt=--strip-all -c opt) - if [[ "$CI_TARGET" == "release" ]]; then + if [[ "$CI_TARGET" == "release" || "$CI_TARGET" == "release.test_only" ]]; then # Run release tests echo "Testing with:" echo " targets: ${TEST_TARGETS[*]}" @@ -865,6 +874,22 @@ case $CI_TARGET in "${BAZEL_RELEASE_OPTIONS[@]}" \ "${TEST_TARGETS[@]}" fi + + if [[ "$CI_TARGET" == "release.test_only" ]]; then + exit 0 + fi + + ENVOY_BINARY_DIR="${ENVOY_BUILD_DIR}/bin" + if [[ -e "${ENVOY_BINARY_DIR}" ]]; then + echo "Existing output directory found (${ENVOY_BINARY_DIR}), removing ..." + rm -rf "${ENVOY_BINARY_DIR}" + fi + mkdir -p "$ENVOY_BINARY_DIR" + + # Build + echo "Building with:" + echo " release options: ${BAZEL_RELEASE_OPTIONS[*]}" + # Build release binaries bazel build "${BAZEL_BUILD_OPTIONS[@]}" \ "${BAZEL_RELEASE_OPTIONS[@]}" \ @@ -903,7 +928,12 @@ case $CI_TARGET in setup_clang_toolchain bazel build "${BAZEL_BUILD_OPTIONS[@]}" //distribution:signed cp -a bazel-bin/distribution/release.signed.tar.zst "${BUILD_DIR}/envoy/" - "${ENVOY_SRCDIR}/ci/upload_gcs_artifact.sh" "${BUILD_DIR}/envoy" release + bazel run //tools/gcs:upload \ + "${GCS_ARTIFACT_BUCKET}" \ + "${GCP_SERVICE_ACCOUNT_KEY_PATH}" \ + "${BUILD_DIR}/envoy" \ + "release" \ + "${GCS_REDIRECT_PATH}" ;; sizeopt) @@ -960,7 +990,13 @@ case $CI_TARGET in ;; verify_examples) - run_ci_verify "*" "win32-front-proxy|shared" + DEV_CONTAINER_ID=$(docker inspect --format='{{.Id}}' envoyproxy/envoy:dev) + bazel run --config=ci \ + --action_env="DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" \ + --host_action_env="DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" \ + --sandbox_writable_path="${HOME}/.docker/" \ + --sandbox_writable_path="$HOME" \ + @envoy_examples//:verify_examples ;; verify.trigger) diff --git a/ci/verify_examples.sh b/ci/verify_examples.sh deleted file mode 100755 index 9e551197f2e9..000000000000 --- a/ci/verify_examples.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash - -set -E - -TESTFILTER="${1:-*}" -TESTEXCLUDES="${2}" -FAILED=() -SRCDIR="${SRCDIR:-$(pwd)}" -WARNINGS=() - -# Sandboxes listed here should be regarded as broken(/untested) until whatever -# is causing them to flake is resolved!!! -FLAKY_SANDBOXES=( - # https://github.com/envoyproxy/envoy/issues/28542 - double-proxy - # https://github.com/envoyproxy/envoy/issues/31347 - local_ratelimit - # https://github.com/envoyproxy/envoy/issues/31333 - locality-load-balancing - # https://github.com/envoyproxy/envoy/issues/33533 - lua-cluster-specifier - # https://github.com/envoyproxy/envoy/issues/28541 - wasm-cc - # https://github.com/envoyproxy/envoy/issues/28546 - websocket) - - -trap_errors () { - local frame=0 command line sub file - for flake in "${FLAKY_SANDBOXES[@]}"; do - if [[ "$example" == "./${flake}" ]]; then - WARNINGS+=("FAILED (${flake})") - return - fi - done - if [[ -n "$example" ]]; then - command=" (${example})" - fi - set +v - while read -r line sub file < <(caller "$frame"); do - if [[ "$frame" -ne "0" ]]; then - FAILED+=(" > ${sub}@ ${file} :${line}") - else - FAILED+=("${sub}@ ${file} :${line}${command}") - fi - ((frame++)) - done - set -v -} - -trap trap_errors ERR -trap exit 1 INT - - -run_examples () { - local examples example - cd "${SRCDIR}/examples" || exit 1 - - examples=$(find . -mindepth 1 -maxdepth 1 -type d -name "$TESTFILTER" ! -iname "_*" | sort) - if [[ -n "$TESTEXCLUDES" ]]; then - examples=$(echo "$examples" | grep -Ev "$TESTEXCLUDES") - fi - for example in $examples; do - pushd "$example" > /dev/null || return 1 - ./verify.sh - popd > /dev/null || return 1 - done -} - -run_examples - -if [[ "${#WARNINGS[@]}" -ne "0" ]]; then - for warning in "${WARNINGS[@]}"; do - echo "WARNING: $warning" >&2 - done -fi - -if [[ "${#FAILED[@]}" -ne "0" ]]; then - echo "TESTS FAILED:" - for failed in "${FAILED[@]}"; do - echo "$failed" >&2 - done - exit 1 -fi diff --git a/configs/BUILD b/configs/BUILD index ab37531ddba9..b0bf82c893ed 100644 --- a/configs/BUILD +++ b/configs/BUILD @@ -53,10 +53,11 @@ genrule( name = "example_configs", srcs = [ ":configs", - "//examples:configs", - "//examples:certs", - "//examples:lua", - "//examples/wasm-cc:configs", + "@envoy_examples//:configs", + "@envoy_examples//:certs", + "@envoy_examples//:lua", + # TODO(phlax): re-enable once wasm example is fixed + # "@envoy_examples//wasm-cc:configs", "//docs:configs", "//docs:proto_examples", "//test/config/integration/certs", @@ -65,10 +66,10 @@ genrule( cmd = ( "$(location configgen.sh) $(location configgen) example_configs.tar $(@D) " + "$(locations :configs) " + - "$(locations //examples:configs) " + - "$(locations //examples:certs) " + - "$(locations //examples:lua) " + - "$(locations //examples/wasm-cc:configs) " + + "$(locations @envoy_examples//:configs) " + + "$(locations @envoy_examples//:certs) " + + "$(locations @envoy_examples//:lua) " + + # "$(locations @envoy_examples//wasm-cc:configs) " + "$(locations //docs:configs) " + "$(locations //docs:proto_examples) " + "$(locations //test/config/integration/certs)" @@ -84,8 +85,8 @@ genrule( srcs = [ "//docs:contrib_configs", "//contrib:configs", - "//examples:contrib_configs", - "//examples:certs", + "@envoy_examples//:contrib_configs", + "@envoy_examples//:certs", "//test/config/integration/certs", ], outs = ["example_contrib_configs.tar"], @@ -93,8 +94,8 @@ genrule( "$(location configgen.sh) NO_CONFIGGEN example_contrib_configs.tar $(@D) " + "$(locations //contrib:configs) " + "$(locations //docs:contrib_configs) " + - "$(locations //examples:contrib_configs) " + - "$(locations //examples:certs) " + + "$(locations @envoy_examples//:contrib_configs) " + + "$(locations @envoy_examples//:certs) " + "$(locations //test/config/integration/certs)" ), tools = [ @@ -109,14 +110,14 @@ py_binary( args = ( "--descriptor_path=$(location @envoy_api//:v3_proto_set)", "$(locations :configs) ", - "$(locations //examples:configs) ", + "$(locations @envoy_examples//:configs) ", "$(locations //docs:configs) ", ), data = [ ":configs", "//docs:configs", - "//examples:configs", "@envoy_api//:v3_proto_set", + "@envoy_examples//:configs", ], deps = [requirement("envoy.base.utils")], ) diff --git a/configs/jwt_authn.yaml b/configs/jwt_authn.yaml new file mode 100644 index 000000000000..725460fdcd9c --- /dev/null +++ b/configs/jwt_authn.yaml @@ -0,0 +1,97 @@ +# An example config to validate JWT tokens issued by Firebase. +admin: + address: + socket_address: + address: 0.0.0.0 + port_value: 9901 +static_resources: + listeners: + - name: listener_0 + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 10000 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager" + stat_prefix: ingress_http + access_log: + - name: envoy.access_loggers.stdout + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog + route_config: + name: local_route + virtual_hosts: + - name: default + domains: + - "*" + routes: + - match: + prefix: "/" + direct_response: + status: 200 + body: + inline_string: "OK" + http_filters: + - name: envoy.extensions.filters.http.jwt_authn + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication + providers: + firebase: + claim_to_headers: + - claim_name: user_id + header_name: x-firebase-uid + - claim_name: firebase.sign_in_provider + header_name: x-firebase-provider + issuer: https://securetoken.google.com/example.com:example-project-1234567890 + audiences: + - example.com:example-project-1234567890 + remoteJwks: + httpUri: + uri: https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com + cluster: www.googleapis.com + timeout: 1s + async_fetch: + fast_listener: false + retry_policy: + num_retries: 10 + forward: true + jwt_cache_config: + jwt_cache_size: 1024 + rules: + - match: + prefix: "/" + requires: + provider_name: firebase + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: www.googleapis.com + type: STRICT_DNS + connect_timeout: 2s + lb_policy: ROUND_ROBIN + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + upstream_http_protocol_options: + auto_sni: true + auto_config: + http2_protocol_options: {} + load_assignment: + cluster_name: www.googleapis.com + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: www.googleapis.com + port_value: 443 + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + sni: www.googleapis.com diff --git a/contrib/golang/common/dso/dso.cc b/contrib/golang/common/dso/dso.cc index ce7336453831..0736854abf5f 100644 --- a/contrib/golang/common/dso/dso.cc +++ b/contrib/golang/common/dso/dso.cc @@ -59,6 +59,9 @@ HttpFilterDsoImpl::HttpFilterDsoImpl(const std::string dso_name) : HttpFilterDso envoy_go_filter_on_http_data_, handler_, dso_name, "envoyGoFilterOnHttpData"); loaded_ &= dlsymInternal( envoy_go_filter_on_http_log_, handler_, dso_name, "envoyGoFilterOnHttpLog"); + loaded_ &= dlsymInternal( + envoy_go_filter_on_http_stream_complete_, handler_, dso_name, + "envoyGoFilterOnHttpStreamComplete"); loaded_ &= dlsymInternal( envoy_go_filter_on_http_destroy_, handler_, dso_name, "envoyGoFilterOnHttpDestroy"); loaded_ &= dlsymInternal( @@ -95,9 +98,17 @@ GoUint64 HttpFilterDsoImpl::envoyGoFilterOnHttpData(processState* p0, GoUint64 p return envoy_go_filter_on_http_data_(p0, p1, p2, p3); } -void HttpFilterDsoImpl::envoyGoFilterOnHttpLog(httpRequest* p0, int p1) { +void HttpFilterDsoImpl::envoyGoFilterOnHttpLog(httpRequest* p0, int p1, processState* p2, + processState* p3, GoUint64 p4, GoUint64 p5, + GoUint64 p6, GoUint64 p7, GoUint64 p8, GoUint64 p9, + GoUint64 p10, GoUint64 p11) { ASSERT(envoy_go_filter_on_http_log_ != nullptr); - envoy_go_filter_on_http_log_(p0, GoUint64(p1)); + envoy_go_filter_on_http_log_(p0, GoUint64(p1), p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +} + +void HttpFilterDsoImpl::envoyGoFilterOnHttpStreamComplete(httpRequest* p0) { + ASSERT(envoy_go_filter_on_http_stream_complete_ != nullptr); + envoy_go_filter_on_http_stream_complete_(p0); } void HttpFilterDsoImpl::envoyGoFilterOnHttpDestroy(httpRequest* p0, int p1) { diff --git a/contrib/golang/common/dso/dso.h b/contrib/golang/common/dso/dso.h index 78c7c0d768ef..1301b1af72b9 100644 --- a/contrib/golang/common/dso/dso.h +++ b/contrib/golang/common/dso/dso.h @@ -43,7 +43,10 @@ class HttpFilterDso : public Dso { GoUint64 p3) PURE; virtual GoUint64 envoyGoFilterOnHttpData(processState* p0, GoUint64 p1, GoUint64 p2, GoUint64 p3) PURE; - virtual void envoyGoFilterOnHttpLog(httpRequest* p0, int p1) PURE; + virtual void envoyGoFilterOnHttpLog(httpRequest* p0, int p1, processState* p2, processState* p3, + GoUint64 p4, GoUint64 p5, GoUint64 p6, GoUint64 p7, + GoUint64 p8, GoUint64 p9, GoUint64 p10, GoUint64 p11) PURE; + virtual void envoyGoFilterOnHttpStreamComplete(httpRequest* p0) PURE; virtual void envoyGoFilterOnHttpDestroy(httpRequest* p0, int p1) PURE; virtual void envoyGoRequestSemaDec(httpRequest* p0) PURE; }; @@ -61,7 +64,10 @@ class HttpFilterDsoImpl : public HttpFilterDso { GoUint64 p3) override; GoUint64 envoyGoFilterOnHttpData(processState* p0, GoUint64 p1, GoUint64 p2, GoUint64 p3) override; - void envoyGoFilterOnHttpLog(httpRequest* p0, int p1) override; + void envoyGoFilterOnHttpLog(httpRequest* p0, int p1, processState* p2, processState* p3, + GoUint64 p4, GoUint64 p5, GoUint64 p6, GoUint64 p7, GoUint64 p8, + GoUint64 p9, GoUint64 p10, GoUint64 p11) override; + void envoyGoFilterOnHttpStreamComplete(httpRequest* p0) override; void envoyGoFilterOnHttpDestroy(httpRequest* p0, int p1) override; void envoyGoRequestSemaDec(httpRequest* p0) override; void cleanup() override; @@ -75,7 +81,11 @@ class HttpFilterDsoImpl : public HttpFilterDso { GoUint64 p3) = {nullptr}; GoUint64 (*envoy_go_filter_on_http_data_)(processState* p0, GoUint64 p1, GoUint64 p2, GoUint64 p3) = {nullptr}; - void (*envoy_go_filter_on_http_log_)(httpRequest* p0, GoUint64 p1) = {nullptr}; + void (*envoy_go_filter_on_http_log_)(httpRequest* p0, int p1, processState* p2, processState* p3, + GoUint64 p4, GoUint64 p5, GoUint64 p6, GoUint64 p7, + GoUint64 p8, GoUint64 p9, GoUint64 p10, + GoUint64 p11) = {nullptr}; + void (*envoy_go_filter_on_http_stream_complete_)(httpRequest* p0) = {nullptr}; void (*envoy_go_filter_on_http_destroy_)(httpRequest* p0, GoUint64 p1) = {nullptr}; void (*envoy_go_filter_go_request_sema_dec_)(httpRequest* p0) = {nullptr}; void (*envoy_go_filter_cleanup_)() = {nullptr}; diff --git a/contrib/golang/common/dso/libgolang.h b/contrib/golang/common/dso/libgolang.h index b477b5b55e6b..eab784cb53ee 100644 --- a/contrib/golang/common/dso/libgolang.h +++ b/contrib/golang/common/dso/libgolang.h @@ -120,7 +120,16 @@ extern GoUint64 envoyGoFilterOnHttpData(processState* s, GoUint64 end_stream, Go // go:linkname envoyGoFilterOnHttpLog // github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http.envoyGoFilterOnHttpLog -extern void envoyGoFilterOnHttpLog(httpRequest* r, GoUint64 type); +extern void envoyGoFilterOnHttpLog(httpRequest* r, GoUint64 type, processState* decoding_state, + processState* encoding_state, GoUint64 req_header_num, + GoUint64 req_header_bytes, GoUint64 req_trailer_num, + GoUint64 req_trailer_bytes, GoUint64 resp_header_num, + GoUint64 resp_header_bytes, GoUint64 resp_trailer_num, + GoUint64 resp_trailer_bytes); + +// go:linkname envoyGoFilterOnHttpStreamComplete +// github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http.envoyGoFilterOnHttpStreamComplete +extern void envoyGoFilterOnHttpStreamComplete(httpRequest* r); // go:linkname envoyGoFilterOnHttpDestroy // github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http.envoyGoFilterOnHttpDestroy diff --git a/contrib/golang/common/dso/test/mocks.h b/contrib/golang/common/dso/test/mocks.h index 973a096bfb10..14247799e829 100644 --- a/contrib/golang/common/dso/test/mocks.h +++ b/contrib/golang/common/dso/test/mocks.h @@ -21,7 +21,11 @@ class MockHttpFilterDsoImpl : public HttpFilterDso { (processState * p0, GoUint64 p1, GoUint64 p2, GoUint64 p3)); MOCK_METHOD(GoUint64, envoyGoFilterOnHttpData, (processState * p0, GoUint64 p1, GoUint64 p2, GoUint64 p3)); - MOCK_METHOD(void, envoyGoFilterOnHttpLog, (httpRequest * p0, int p1)); + MOCK_METHOD(void, envoyGoFilterOnHttpLog, + (httpRequest * p0, int p1, processState* p2, processState* p3, GoUint64 p4, + GoUint64 p5, GoUint64 p6, GoUint64 p7, GoUint64 p8, GoUint64 p9, GoUint64 p10, + GoUint64 p11)); + MOCK_METHOD(void, envoyGoFilterOnHttpStreamComplete, (httpRequest * p0)); MOCK_METHOD(void, envoyGoFilterOnHttpDestroy, (httpRequest * p0, int p1)); MOCK_METHOD(void, envoyGoRequestSemaDec, (httpRequest * p0)); MOCK_METHOD(void, envoyGoFilterCleanUp, ()); diff --git a/contrib/golang/common/dso/test/test_data/simple.go b/contrib/golang/common/dso/test/test_data/simple.go index a0ce2419bb2f..22d36a1cbd3e 100644 --- a/contrib/golang/common/dso/test/test_data/simple.go +++ b/contrib/golang/common/dso/test/test_data/simple.go @@ -57,7 +57,13 @@ func envoyGoFilterOnHttpData(s *C.processState, endStream, buffer, length uint64 } //export envoyGoFilterOnHttpLog -func envoyGoFilterOnHttpLog(r *C.httpRequest, logType uint64) { +func envoyGoFilterOnHttpLog(r *C.httpRequest, logType uint64, decodingState *C.processState, encodingState *C.processState, + reqHeaderNum, reqHeaderBytes, reqTrailerNum, reqTrailerBytes, + respHeaderNum, respHeaderBytes, respTrailerNum, respTrailerBytes uint64) { +} + +//export envoyGoFilterOnHttpStreamComplete +func envoyGoFilterOnHttpStreamComplete(r *C.httpRequest) { } //export envoyGoFilterOnHttpDestroy diff --git a/contrib/golang/common/go/api/api.h b/contrib/golang/common/go/api/api.h index e6825f04e9fe..fb99623b7721 100644 --- a/contrib/golang/common/go/api/api.h +++ b/contrib/golang/common/go/api/api.h @@ -3,7 +3,13 @@ // NOLINT(namespace-envoy) #ifdef __cplusplus +#include + +#define _Atomic(X) std::atomic + extern "C" { +#else +#include // NOLINT(modernize-deprecated-headers) #endif #include // NOLINT(modernize-deprecated-headers) @@ -27,6 +33,8 @@ typedef struct httpRequest { // NOLINT(modernize-use-using) // The ID of the worker that is processing this request, this enables the go filter to dedicate // memory to each worker and not require locks uint32_t worker_id; + // This flag will be read & written by different threads, so it need to be atomic + _Atomic(int) is_golang_processing_log; } httpRequest; typedef struct { // NOLINT(modernize-use-using) diff --git a/contrib/golang/common/go/api/filter.go b/contrib/golang/common/go/api/filter.go index f33e1e90ae71..43ba5507f251 100644 --- a/contrib/golang/common/go/api/filter.go +++ b/contrib/golang/common/go/api/filter.go @@ -81,27 +81,30 @@ type StreamFilter interface { StreamEncoderFilter // log - OnLog() - OnLogDownstreamStart() - OnLogDownstreamPeriodic() + OnLog(RequestHeaderMap, RequestTrailerMap, ResponseHeaderMap, ResponseTrailerMap) + OnLogDownstreamStart(RequestHeaderMap) + OnLogDownstreamPeriodic(RequestHeaderMap, RequestTrailerMap, ResponseHeaderMap, ResponseTrailerMap) // destroy filter OnDestroy(DestroyReason) - // TODO add more for stream complete + OnStreamComplete() } -func (*PassThroughStreamFilter) OnLog() { +func (*PassThroughStreamFilter) OnLog(RequestHeaderMap, RequestTrailerMap, ResponseHeaderMap, ResponseTrailerMap) { } -func (*PassThroughStreamFilter) OnLogDownstreamStart() { +func (*PassThroughStreamFilter) OnLogDownstreamStart(RequestHeaderMap) { } -func (*PassThroughStreamFilter) OnLogDownstreamPeriodic() { +func (*PassThroughStreamFilter) OnLogDownstreamPeriodic(RequestHeaderMap, RequestTrailerMap, ResponseHeaderMap, ResponseTrailerMap) { } func (*PassThroughStreamFilter) OnDestroy(DestroyReason) { } +func (*PassThroughStreamFilter) OnStreamComplete() { +} + type StreamFilterConfigParser interface { // Parse the proto message to any Go value, and return error to reject the config. // This is called when Envoy receives the config from the control plane. diff --git a/contrib/golang/filters/http/source/go/pkg/http/shim.go b/contrib/golang/filters/http/source/go/pkg/http/shim.go index c904ee5f98a2..8b2ffc1a88d7 100644 --- a/contrib/golang/filters/http/source/go/pkg/http/shim.go +++ b/contrib/golang/filters/http/source/go/pkg/http/shim.go @@ -266,7 +266,13 @@ func envoyGoFilterOnHttpData(s *C.processState, endStream, buffer, length uint64 } //export envoyGoFilterOnHttpLog -func envoyGoFilterOnHttpLog(r *C.httpRequest, logType uint64) { +func envoyGoFilterOnHttpLog(r *C.httpRequest, logType uint64, + decodingStateWrapper *C.processState, encodingStateWrapper *C.processState, + reqHeaderNum, reqHeaderBytes, reqTrailerNum, reqTrailerBytes, + respHeaderNum, respHeaderBytes, respTrailerNum, respTrailerBytes uint64) { + + decodingState := getOrCreateState(decodingStateWrapper) + encodingState := getOrCreateState(encodingStateWrapper) req := getRequest(r) if req == nil { req = createRequest(r) @@ -276,19 +282,81 @@ func envoyGoFilterOnHttpLog(r *C.httpRequest, logType uint64) { v := api.AccessLogType(logType) + // Request headers must exist because the HTTP filter won't be run if the headers are + // not sent yet. + // TODO: make the headers/trailers read-only + reqHeader := &requestHeaderMapImpl{ + requestOrResponseHeaderMapImpl{ + headerMapImpl{ + state: decodingState, + headerNum: reqHeaderNum, + headerBytes: reqHeaderBytes, + }, + }, + } + + var reqTrailer api.RequestTrailerMap + if reqTrailerNum != 0 { + reqTrailer = &requestTrailerMapImpl{ + requestOrResponseTrailerMapImpl{ + headerMapImpl{ + state: decodingState, + headerNum: reqTrailerNum, + headerBytes: reqTrailerBytes, + }, + }, + } + } + + var respHeader api.ResponseHeaderMap + if respHeaderNum != 0 { + respHeader = &responseHeaderMapImpl{ + requestOrResponseHeaderMapImpl{ + headerMapImpl{ + state: encodingState, + headerNum: respHeaderNum, + headerBytes: respHeaderBytes, + }, + }, + } + } + + var respTrailer api.ResponseTrailerMap + if respTrailerNum != 0 { + respTrailer = &responseTrailerMapImpl{ + requestOrResponseTrailerMapImpl{ + headerMapImpl{ + state: encodingState, + headerNum: respTrailerNum, + headerBytes: respTrailerBytes, + }, + }, + } + } + f := req.httpFilter + switch v { - case api.AccessLogDownstreamStart: - f.OnLogDownstreamStart() - case api.AccessLogDownstreamPeriodic: - f.OnLogDownstreamPeriodic() case api.AccessLogDownstreamEnd: - f.OnLog() + f.OnLog(reqHeader, reqTrailer, respHeader, respTrailer) + case api.AccessLogDownstreamPeriodic: + f.OnLogDownstreamPeriodic(reqHeader, reqTrailer, respHeader, respTrailer) + case api.AccessLogDownstreamStart: + f.OnLogDownstreamStart(reqHeader) default: api.LogErrorf("access log type %d is not supported yet", logType) } } +//export envoyGoFilterOnHttpStreamComplete +func envoyGoFilterOnHttpStreamComplete(r *C.httpRequest) { + req := getRequest(r) + defer req.recoverPanic() + + f := req.httpFilter + f.OnStreamComplete() +} + //export envoyGoFilterOnHttpDestroy func envoyGoFilterOnHttpDestroy(r *C.httpRequest, reason uint64) { req := getRequest(r) diff --git a/contrib/golang/filters/http/source/golang_filter.cc b/contrib/golang/filters/http/source/golang_filter.cc index 486d16da589d..b181b6142c52 100644 --- a/contrib/golang/filters/http/source/golang_filter.cc +++ b/contrib/golang/filters/http/source/golang_filter.cc @@ -77,6 +77,8 @@ Http::FilterTrailersStatus Filter::decodeTrailers(Http::RequestTrailerMap& trail ProcessorState& state = decoding_state_; ENVOY_LOG(debug, "golang filter decodeTrailers, decoding state: {}", state.stateStr()); + request_trailers_ = &trailers; + bool done = doTrailer(state, trailers); return done ? Http::FilterTrailersStatus::Continue : Http::FilterTrailersStatus::StopIteration; @@ -91,10 +93,10 @@ Http::FilterHeadersStatus Filter::encodeHeaders(Http::ResponseHeaderMap& headers activation_response_headers_ = dynamic_cast(&headers); // NP: may enter encodeHeaders in any state, - // since other filters or filtermanager could call encodeHeaders or sendLocalReply in any time. - // eg. filtermanager may invoke sendLocalReply, when scheme is invalid, - // with "Sending local reply with details // http1.invalid_scheme" details. - // This means DecodeXXX & EncodeXXX may run concurrently in Golang side. + // since other filters or filtermanager could call encodeHeaders or sendLocalReply in any + // time. eg. filtermanager may invoke sendLocalReply, when scheme is invalid, with "Sending + // local reply with details // http1.invalid_scheme" details. This means DecodeXXX & EncodeXXX + // may run concurrently in Golang side. bool done = doHeaders(encoding_state_, headers, end_stream); @@ -129,6 +131,14 @@ Http::FilterTrailersStatus Filter::encodeTrailers(Http::ResponseTrailerMap& trai return done ? Http::FilterTrailersStatus::Continue : Http::FilterTrailersStatus::StopIteration; } +void Filter::onStreamComplete() { + // We reuse the same flag for both onStreamComplete & log to save the space, + // since they are exclusive and serve for the access log purpose. + req_->is_golang_processing_log = 1; + dynamic_lib_->envoyGoFilterOnHttpStreamComplete(req_); + req_->is_golang_processing_log = 0; +} + void Filter::onDestroy() { ENVOY_LOG(debug, "golang filter on destroy"); @@ -159,6 +169,18 @@ void Filter::onDestroy() { // access_log is executed before the log of the stream filter void Filter::log(const Formatter::HttpFormatterContext& log_context, const StreamInfo::StreamInfo&) { + uint64_t req_header_num = 0; + uint64_t req_header_bytes = 0; + uint64_t req_trailer_num = 0; + uint64_t req_trailer_bytes = 0; + uint64_t resp_header_num = 0; + uint64_t resp_header_bytes = 0; + uint64_t resp_trailer_num = 0; + uint64_t resp_trailer_bytes = 0; + + auto decoding_state = dynamic_cast(&decoding_state_); + auto encoding_state = dynamic_cast(&encoding_state_); + // `log` may be called multiple times with different log type switch (log_context.accessLogType()) { case Envoy::AccessLog::AccessLogType::DownstreamStart: @@ -166,14 +188,42 @@ void Filter::log(const Formatter::HttpFormatterContext& log_context, case Envoy::AccessLog::AccessLogType::DownstreamEnd: // log called by AccessLogDownstreamStart will happen before doHeaders if (initRequest()) { - request_headers_ = static_cast( - const_cast(&log_context.requestHeaders())); + request_headers_ = const_cast(&log_context.requestHeaders()); + } + + if (request_headers_ != nullptr) { + req_header_num = request_headers_->size(); + req_header_bytes = request_headers_->byteSize(); + decoding_state_.headers = request_headers_; + } + + if (request_trailers_ != nullptr) { + req_trailer_num = request_trailers_->size(); + req_trailer_bytes = request_trailers_->byteSize(); + decoding_state_.trailers = request_trailers_; + } + + activation_response_headers_ = &log_context.responseHeaders(); + if (activation_response_headers_ != nullptr) { + resp_header_num = activation_response_headers_->size(); + resp_header_bytes = activation_response_headers_->byteSize(); + encoding_state_.headers = const_cast(activation_response_headers_); + } + + activation_response_trailers_ = &log_context.responseTrailers(); + if (activation_response_trailers_ != nullptr) { + resp_trailer_num = activation_response_trailers_->size(); + resp_trailer_bytes = activation_response_trailers_->byteSize(); + encoding_state_.trailers = + const_cast(activation_response_trailers_); } - // This only run in the work thread, it's safe even without lock. - is_golang_processing_log_ = true; - dynamic_lib_->envoyGoFilterOnHttpLog(req_, int(log_context.accessLogType())); - is_golang_processing_log_ = false; + req_->is_golang_processing_log = 1; + dynamic_lib_->envoyGoFilterOnHttpLog(req_, int(log_context.accessLogType()), decoding_state, + encoding_state, req_header_num, req_header_bytes, + req_trailer_num, req_trailer_bytes, resp_header_num, + resp_header_bytes, resp_trailer_num, resp_trailer_bytes); + req_->is_golang_processing_log = 0; break; default: // skip calling with unsupported log types @@ -1127,7 +1177,7 @@ CAPIStatus Filter::getStringProperty(absl::string_view path, uint64_t* value_dat } // to access the headers_ and its friends we need to hold the lock - activation_request_headers_ = dynamic_cast(request_headers_); + activation_request_headers_ = request_headers_; if (isThreadSafe()) { return getStringPropertyCommon(path, value_data, value_len); diff --git a/contrib/golang/filters/http/source/golang_filter.h b/contrib/golang/filters/http/source/golang_filter.h index f3a9a461c7e6..651903e94f37 100644 --- a/contrib/golang/filters/http/source/golang_filter.h +++ b/contrib/golang/filters/http/source/golang_filter.h @@ -223,6 +223,7 @@ class Filter : public Http::StreamFilter, } // Http::StreamFilterBase + void onStreamComplete() override; void onDestroy() ABSL_LOCKS_EXCLUDED(mutex_) override; Http::LocalErrorStatus onLocalReply(const LocalReplyData&) override; @@ -255,8 +256,6 @@ class Filter : public Http::StreamFilter, void log(const Formatter::HttpFormatterContext& log_context, const StreamInfo::StreamInfo& info) override; - void onStreamComplete() override {} - CAPIStatus clearRouteCache(); CAPIStatus continueStatus(ProcessorState& state, GolangStatus status); @@ -293,8 +292,7 @@ class Filter : public Http::StreamFilter, GoInt32* rc); bool isProcessingInGo() { - return is_golang_processing_log_ || decoding_state_.isProcessingInGo() || - encoding_state_.isProcessingInGo(); + return decoding_state_.isProcessingInGo() || encoding_state_.isProcessingInGo(); } void deferredDeleteRequest(HttpRequestInternal* req); @@ -346,7 +344,8 @@ class Filter : public Http::StreamFilter, // save temp values for fetching request attributes in the later phase, // like getting request size - Http::RequestOrResponseHeaderMap* request_headers_{nullptr}; + Http::RequestHeaderMap* request_headers_{nullptr}; + Http::RequestTrailerMap* request_trailers_{nullptr}; HttpRequestInternal* req_{nullptr}; @@ -360,8 +359,6 @@ class Filter : public Http::StreamFilter, // back from go). Thread::MutexBasicLockable mutex_{}; bool has_destroyed_ ABSL_GUARDED_BY(mutex_){false}; - - bool is_golang_processing_log_{false}; }; struct httpConfigInternal : httpConfig { diff --git a/contrib/golang/filters/http/source/processor_state.h b/contrib/golang/filters/http/source/processor_state.h index d537d68a327c..9c030040561e 100644 --- a/contrib/golang/filters/http/source/processor_state.h +++ b/contrib/golang/filters/http/source/processor_state.h @@ -95,7 +95,7 @@ class ProcessorState : public processState, public Logger::Loggableis_golang_processing_log; } bool isProcessingHeader() { return filterState() == FilterState::ProcessingHeader; } diff --git a/contrib/golang/filters/http/test/golang_filter_fuzz_test.cc b/contrib/golang/filters/http/test/golang_filter_fuzz_test.cc index c34b4cc1accb..4c777a0b01f4 100644 --- a/contrib/golang/filters/http/test/golang_filter_fuzz_test.cc +++ b/contrib/golang/filters/http/test/golang_filter_fuzz_test.cc @@ -54,8 +54,12 @@ DEFINE_PROTO_FUZZER(const envoy::extensions::filters::http::golang::GolangFilter .WillByDefault(Return(static_cast(GolangStatus::Continue))); ON_CALL(*dso_lib.get(), envoyGoFilterOnHttpData(_, _, _, _)) .WillByDefault(Return(static_cast(GolangStatus::Continue))); - ON_CALL(*dso_lib.get(), envoyGoFilterOnHttpLog(_, _)) - .WillByDefault(Invoke([&](httpRequest*, int) -> void {})); + ON_CALL(*dso_lib.get(), envoyGoFilterOnHttpLog(_, _, _, _, _, _, _, _, _, _, _, _)) + .WillByDefault( + Invoke([&](httpRequest*, int, processState*, processState*, GoUint64, GoUint64, GoUint64, + GoUint64, GoUint64, GoUint64, GoUint64, GoUint64) -> void {})); + ON_CALL(*dso_lib.get(), envoyGoFilterOnHttpStreamComplete(_)) + .WillByDefault(Invoke([&](httpRequest*) -> void {})); ON_CALL(*dso_lib.get(), envoyGoFilterOnHttpDestroy(_, _)) .WillByDefault(Invoke([&](httpRequest* p0, int) -> void { // delete the filter->req_, make LeakSanitizer happy. diff --git a/contrib/golang/filters/http/test/golang_integration_test.cc b/contrib/golang/filters/http/test/golang_integration_test.cc index cddf317e9368..d51d968413d1 100644 --- a/contrib/golang/filters/http/test/golang_integration_test.cc +++ b/contrib/golang/filters/http/test/golang_integration_test.cc @@ -11,6 +11,8 @@ namespace Envoy { +using testing::HasSubstr; + // helper function absl::string_view getHeader(const Http::HeaderMap& headers, absl::string_view key) { auto values = headers.get(Http::LowerCaseString(key)); @@ -888,21 +890,25 @@ TEST_P(GolangIntegrationTest, Property) { } TEST_P(GolangIntegrationTest, AccessLog) { + useAccessLog("%DYNAMIC_METADATA(golang:access_log_var)%"); initializeBasicFilter(ACCESSLOG, "test.com"); auto path = "/test"; codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); Http::TestRequestHeaderMapImpl request_headers{ - {":method", "POST"}, - {":path", path}, - {":scheme", "http"}, - {":authority", "test.com"}, + {":method", "POST"}, {":path", path}, {":scheme", "http"}, + {":authority", "test.com"}, {"Referer", "r"}, }; auto encoder_decoder = codec_client_->startRequest(request_headers); Http::RequestEncoder& request_encoder = encoder_decoder.first; auto response = std::move(encoder_decoder.second); - codec_client_->sendData(request_encoder, "helloworld", true); + codec_client_->sendData(request_encoder, "helloworld", false); + + Http::TestRequestTrailerMapImpl request_trailers{ + {"x-trailer", "foo"}, + }; + codec_client_->sendTrailers(request_encoder, request_trailers); waitForNextUpstreamRequest(); @@ -913,11 +919,17 @@ TEST_P(GolangIntegrationTest, AccessLog) { Buffer::OwnedImpl response_data1("good"); upstream_request_->encodeData(response_data1, false); Buffer::OwnedImpl response_data2("bye"); - upstream_request_->encodeData(response_data2, true); + upstream_request_->encodeData(response_data2, false); + + Http::TestResponseTrailerMapImpl response_trailers{{"x-trailer", "bar"}}; + upstream_request_->encodeTrailers(response_trailers); ASSERT_TRUE(response->waitForEndStream()); codec_client_->close(); + std::string log = waitForAccessLog(access_log_name_); + EXPECT_THAT(log, HasSubstr("access_log_var written by Golang filter")); + // use the second request to get the logged data codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http")))); response = sendRequestAndWaitForResponse(request_headers, 0, default_response_headers_, 0); @@ -927,6 +939,8 @@ TEST_P(GolangIntegrationTest, AccessLog) { EXPECT_EQ("206", getHeader(upstream_request_->headers(), "respCode")); EXPECT_EQ("7", getHeader(upstream_request_->headers(), "respSize")); EXPECT_EQ("true", getHeader(upstream_request_->headers(), "canRunAsyncly")); + EXPECT_EQ("foo", getHeader(upstream_request_->headers(), "x-req-trailer")); + EXPECT_EQ("bar", getHeader(upstream_request_->headers(), "x-resp-trailer")); cleanup(); } diff --git a/contrib/golang/filters/http/test/test_data/access_log/filter.go b/contrib/golang/filters/http/test/test_data/access_log/filter.go index 8b7e8233f630..ecace4cdd4fb 100644 --- a/contrib/golang/filters/http/test/test_data/access_log/filter.go +++ b/contrib/golang/filters/http/test/test_data/access_log/filter.go @@ -22,6 +22,9 @@ var ( canRunAsynclyForDownstreamPeriodic bool referers = []string{} + + xReqTrailer string + xRespTrailer string ) type filter struct { @@ -61,18 +64,26 @@ func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api. // the counter will be 0 when this request is ended counter = -1 + header.Set("x-req-trailer", xReqTrailer) + header.Set("x-resp-trailer", xRespTrailer) } return api.Continue } -func (f *filter) OnLogDownstreamStart() { +func (f *filter) OnLogDownstreamStart(reqHeader api.RequestHeaderMap) { referer, err := f.callbacks.GetProperty("request.referer") if err != nil { api.LogErrorf("err: %s", err) return } + refererFromHdr, _ := reqHeader.Get("referer") + if referer != refererFromHdr { + api.LogErrorf("referer from property: %s, referer from header: %s", referer, refererFromHdr) + return + } + referers = append(referers, referer) wg.Add(1) @@ -83,13 +94,19 @@ func (f *filter) OnLogDownstreamStart() { }() } -func (f *filter) OnLogDownstreamPeriodic() { +func (f *filter) OnLogDownstreamPeriodic(reqHeader api.RequestHeaderMap, reqTrailer api.RequestTrailerMap, respHeader api.ResponseHeaderMap, respTrailer api.ResponseTrailerMap) { referer, err := f.callbacks.GetProperty("request.referer") if err != nil { api.LogErrorf("err: %s", err) return } + refererFromHdr, _ := reqHeader.Get("referer") + if referer != refererFromHdr { + api.LogErrorf("referer from property: %s, referer from header: %s", referer, refererFromHdr) + return + } + referers = append(referers, referer) wg.Add(1) @@ -100,13 +117,44 @@ func (f *filter) OnLogDownstreamPeriodic() { }() } -func (f *filter) OnLog() { +func (f *filter) OnStreamComplete() { + f.callbacks.StreamInfo().DynamicMetadata().Set("golang", "access_log_var", "access_log_var written by Golang filter") +} + +func (f *filter) OnLog(reqHeader api.RequestHeaderMap, reqTrailer api.RequestTrailerMap, respHeader api.ResponseHeaderMap, respTrailer api.ResponseTrailerMap) { + referer, err := f.callbacks.GetProperty("request.referer") + if err != nil { + api.LogErrorf("err: %s", err) + return + } + + refererFromHdr, _ := reqHeader.Get("referer") + if referer != refererFromHdr { + api.LogErrorf("referer from property: %s, referer from header: %s", referer, refererFromHdr) + return + } + + if reqTrailer != nil { + xReqTrailer, _ = reqTrailer.Get("x-trailer") + } + code, ok := f.callbacks.StreamInfo().ResponseCode() if !ok { return } respCode = strconv.Itoa(int(code)) api.LogCritical(respCode) + + status, _ := respHeader.Get(":status") + if status != respCode { + api.LogErrorf("status from StreamInfo: %s, status from header: %s", respCode, status) + return + } + + if respTrailer != nil { + xRespTrailer, _ = respTrailer.Get("x-trailer") + } + size, err := f.callbacks.GetProperty("response.size") if err != nil { api.LogErrorf("err: %s", err) diff --git a/contrib/golang/filters/http/test/test_data/basic/filter.go b/contrib/golang/filters/http/test/test_data/basic/filter.go index 680980979cef..ca1c8dadf0da 100644 --- a/contrib/golang/filters/http/test/test_data/basic/filter.go +++ b/contrib/golang/filters/http/test/test_data/basic/filter.go @@ -546,7 +546,7 @@ func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType } } -func (f *filter) OnLog() { +func (f *filter) OnLog(reqHeader api.RequestHeaderMap, reqTrailer api.RequestTrailerMap, respHeader api.ResponseHeaderMap, respTrailer api.ResponseTrailerMap) { api.LogError("call log in OnLog") } diff --git a/contrib/golang/filters/http/test/test_data/property/filter.go b/contrib/golang/filters/http/test/test_data/property/filter.go index 9f77dd5382f9..e61df65f2392 100644 --- a/contrib/golang/filters/http/test/test_data/property/filter.go +++ b/contrib/golang/filters/http/test/test_data/property/filter.go @@ -129,7 +129,7 @@ func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.Statu return api.Continue } -func (f *filter) OnLog() { +func (f *filter) OnLog(reqHeader api.RequestHeaderMap, reqTrailer api.RequestTrailerMap, respHeader api.ResponseHeaderMap, respTrailer api.ResponseTrailerMap) { f.assertProperty("response.size", "7") // "goodbye" // panic if any condition is not met diff --git a/contrib/vcl/source/BUILD b/contrib/vcl/source/BUILD index ee8caf6184b9..b8b3de1f7044 100644 --- a/contrib/vcl/source/BUILD +++ b/contrib/vcl/source/BUILD @@ -57,7 +57,7 @@ envoy_cmake( postfix_script = """ mkdir -p $INSTALLDIR/lib/external $INSTALLDIR/include/external \ && find . -name "*.a" | xargs -I{} cp -a {} $INSTALLDIR/lib/ \ - && find . -name "*.h" | xargs -I{} cp -a {} $INSTALLDIR/include + && find . -name "*.h" ! -name config.h | xargs -I{} cp -a {} $INSTALLDIR/include """, tags = [ "cpu:16", diff --git a/docs/BUILD b/docs/BUILD index 46df13e77e19..7ad25e7b18c4 100644 --- a/docs/BUILD +++ b/docs/BUILD @@ -236,7 +236,7 @@ pkg_tar( ":extensions_security_rst", ":external_deps_rst", ":version_history_rst", - "//examples:docs", + "@envoy_examples//:docs", ], ) diff --git a/docs/root/api-v3/common_messages/common_messages.rst b/docs/root/api-v3/common_messages/common_messages.rst index a1f3488a86d8..0b5c9032b933 100644 --- a/docs/root/api-v3/common_messages/common_messages.rst +++ b/docs/root/api-v3/common_messages/common_messages.rst @@ -31,6 +31,7 @@ Common messages ../extensions/early_data/v3/default_early_data_policy.proto ../config/core/v3/http_uri.proto ../extensions/matching/input_matchers/ip/v3/ip.proto + ../extensions/matching/input_matchers/metadata/v3/metadata.proto ../extensions/matching/input_matchers/runtime_fraction/v3/runtime_fraction.proto ../config/core/v3/address.proto ../config/core/v3/protocol.proto diff --git a/docs/root/configuration/advanced/well_known_filter_state.rst b/docs/root/configuration/advanced/well_known_filter_state.rst index f238dd207854..edcfc2e321ff 100644 --- a/docs/root/configuration/advanced/well_known_filter_state.rst +++ b/docs/root/configuration/advanced/well_known_filter_state.rst @@ -68,6 +68,11 @@ The following lists the filter state object keys used by the Envoy extensions: ` override on a per-connection basis. Accepts a count of milliseconds number string as a constructor. +``envoy.ratelimit.hits_addend`` + :ref:`Rate Limit Hits Addend + ` override on a per-route basis. + Accepts a number string as a constructor. + Filter state object fields -------------------------- diff --git a/docs/root/configuration/http/http_conn_man/stats.rst b/docs/root/configuration/http/http_conn_man/stats.rst index 2605414255a1..fbd4e3ba4a69 100644 --- a/docs/root/configuration/http/http_conn_man/stats.rst +++ b/docs/root/configuration/http/http_conn_man/stats.rst @@ -26,6 +26,7 @@ statistics: ``downstream_cx_ssl_active``, Gauge, Total active TLS connections ``downstream_cx_http1_active``, Gauge, Total active HTTP/1.1 connections ``downstream_cx_upgrades_active``, Gauge, Total active upgraded connections. These are also counted as active http1/http2 connections. + ``downstream_cx_http1_soft_drain``, Gauge, Total active HTTP/1.x connections waiting for another downstream request to safely close the connection. ``downstream_cx_http2_active``, Gauge, Total active HTTP/2 connections ``downstream_cx_http3_active``, Gauge, Total active HTTP/3 connections ``downstream_cx_protocol_error``, Counter, Total protocol errors diff --git a/docs/root/configuration/http/http_filters/oauth2_filter.rst b/docs/root/configuration/http/http_filters/oauth2_filter.rst index a38a32858304..40a17d3fca9c 100644 --- a/docs/root/configuration/http/http_filters/oauth2_filter.rst +++ b/docs/root/configuration/http/http_filters/oauth2_filter.rst @@ -41,7 +41,7 @@ with the same value. The OAuth filter encodes URLs in query parameters using the `URL encoding algorithm. `_ -When receiving request redirected from the authorization service the Oauth filer decodes URLs from query parameters. +When receiving request redirected from the authorization service the Oauth filter decodes URLs from query parameters. However the encoded character sequences that represent ASCII control characters or extended ASCII codepoints are not decoded. The characters without defined meaning in URL according to `RFC 3986 `_ are also left undecoded. Specifically the following characters are left in the encoded form: @@ -252,8 +252,8 @@ during those requests by enabling the :ref:`use_refresh_token ` provides -possibility to update access token by using a refresh token. By default after expiration the user is always redirected to the authorization endpoint to log in again. -By enabling this flag a new access token is obtained using by a refresh token without redirecting the user to log in again. This requires the refresh token to be provided by authorization_endpoint when the user logs in. +the possibility to update access token by using a refresh token. By default after expiration the user is always redirected to the authorization endpoint to log in again. +By enabling this flag a new access token is obtained using the refresh token without redirecting the user to log in again. This requires the refresh token to be provided by the authorization_endpoint when the user logs in. If the attempt to get an access token by using a refresh token fails then the user is redirected to the authorization endpoint as usual. Generally, allowlisting is inadvisable from a security standpoint. diff --git a/docs/root/configuration/observability/access_log/usage.rst b/docs/root/configuration/observability/access_log/usage.rst index 657c485a9b7d..d0fc7098e53e 100644 --- a/docs/root/configuration/observability/access_log/usage.rst +++ b/docs/root/configuration/observability/access_log/usage.rst @@ -1111,6 +1111,24 @@ UDP UDP Not implemented ("-"). +%DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256% + HTTP/TCP/THRIFT + The comma-separated hex-encoded SHA256 fingerprints of all client certificates used to establish the downstream TLS connection. + UDP + Not implemented ("-"). + +%DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1% + HTTP/TCP/THRIFT + The comma-separated hex-encoded SHA1 fingerprints of all client certificates used to establish the downstream TLS connection. + UDP + Not implemented ("-"). + +%DOWNSTREAM_PEER_CHAIN_SERIALS% + HTTP/TCP/THRIFT + The comma-separated wserial numbers of all client certificates used to establish the downstream TLS connection. + UDP + Not implemented ("-"). + %DOWNSTREAM_PEER_CERT% HTTP/TCP/THRIFT The client certificate in the URL-encoded PEM format used to establish the downstream TLS connection. diff --git a/docs/root/intro/arch_overview/advanced/matching/matching_api.rst b/docs/root/intro/arch_overview/advanced/matching/matching_api.rst index 8876c47814b6..09ac66e2539f 100644 --- a/docs/root/intro/arch_overview/advanced/matching/matching_api.rst +++ b/docs/root/intro/arch_overview/advanced/matching/matching_api.rst @@ -30,6 +30,7 @@ These input functions are available for matching HTTP requests: * :ref:`Response header value `. * :ref:`Response trailer value `. * :ref:`Query parameters value `. +* :ref:`Dynamic metadata `. .. _extension_category_envoy.matching.network.input: diff --git a/docs/root/intro/arch_overview/other_protocols/redis.rst b/docs/root/intro/arch_overview/other_protocols/redis.rst index 72e3000c1944..6fb54f1a834b 100644 --- a/docs/root/intro/arch_overview/other_protocols/redis.rst +++ b/docs/root/intro/arch_overview/other_protocols/redis.rst @@ -200,6 +200,7 @@ For details on each command's usage see the official RPOP, List RPUSH, List RPUSHX, List + PUBLISH, Pubsub EVAL, Scripting EVALSHA, Scripting SADD, Set diff --git a/docs/root/operations/cli.rst b/docs/root/operations/cli.rst index cd33505380dc..aeb70858a233 100644 --- a/docs/root/operations/cli.rst +++ b/docs/root/operations/cli.rst @@ -109,6 +109,7 @@ following are the command line options that Envoy supports. never set this option. For example, if you want ``upstream`` component to run at ``debug`` level and ``connection`` component to run at ``trace`` level, you should pass ``upstream:debug,connection:trace`` to this flag. See ``ALL_LOGGER_IDS`` in :repo:`/source/common/common/logger.h` for a list of components. + This option is incompatible with :option:`--enable-fine-grain-logging`. .. option:: --cpuset-threads @@ -193,7 +194,7 @@ following are the command line options that Envoy supports. interface. If enabled, main log macros including ``ENVOY_LOG``, ``ENVOY_CONN_LOG``, ``ENVOY_STREAM_LOG`` and ``ENVOY_FLUSH_LOG`` will use a per-file logger, and the usage doesn't need ``Envoy::Logger::Loggable`` any more. The administration interface usage is similar. Please see :ref:`Administration interface - ` for more detail. + ` for more detail. This option is incompatible with :option:`--component-log-level`. .. option:: --socket-path diff --git a/envoy/common/exception.h b/envoy/common/exception.h index 327fa906c0fb..0688b440dfbc 100644 --- a/envoy/common/exception.h +++ b/envoy/common/exception.h @@ -57,15 +57,14 @@ class EnvoyException : public std::runtime_error { // the macros above. #define THROW_IF_STATUS_NOT_OK(variable, throw_action) THROW_IF_NOT_OK_REF(variable.status()); -// TODO(alyssawilk) remove in favor of RETURN_IF_NOT_OK -#define RETURN_IF_STATUS_NOT_OK(variable) \ - if (!variable.status().ok()) { \ - return variable.status(); \ +#define RETURN_IF_NOT_OK_REF(variable) \ + if (const absl::Status& temp_status = variable; !temp_status.ok()) { \ + return temp_status; \ } // Make sure this works for functions without calling the functoin twice as well. -#define RETURN_IF_NOT_OK(variable) \ - if (absl::Status temp_status = variable; !temp_status.ok()) { \ +#define RETURN_IF_NOT_OK(status_fn) \ + if (absl::Status temp_status = (status_fn); !temp_status.ok()) { \ return temp_status; \ } diff --git a/envoy/formatter/substitution_formatter_base.h b/envoy/formatter/substitution_formatter_base.h index 04b9b1fb25e7..459712a5919d 100644 --- a/envoy/formatter/substitution_formatter_base.h +++ b/envoy/formatter/substitution_formatter_base.h @@ -81,8 +81,8 @@ template class CommandParserBase { * @return FormattterProviderPtr substitution provider for the parsed command. */ virtual FormatterProviderBasePtr - parse(const std::string& command, const std::string& command_arg, - absl::optional& max_length) const PURE; + parse(absl::string_view command, absl::string_view command_arg, + absl::optional max_length) const PURE; }; template diff --git a/envoy/grpc/async_client.h b/envoy/grpc/async_client.h index d263b128fd78..eea2a37701b4 100644 --- a/envoy/grpc/async_client.h +++ b/envoy/grpc/async_client.h @@ -70,6 +70,7 @@ class RawAsyncStream { * @returns the stream info object associated with this stream. */ virtual const StreamInfo::StreamInfo& streamInfo() const PURE; + virtual StreamInfo::StreamInfo& streamInfo() PURE; /*** * Register a callback to be called when high/low write buffer watermark events occur on the diff --git a/envoy/http/async_client.h b/envoy/http/async_client.h index 24e47c136038..e48c50b2de8c 100644 --- a/envoy/http/async_client.h +++ b/envoy/http/async_client.h @@ -234,6 +234,7 @@ class AsyncClient { * @returns the stream info object associated with the stream. */ virtual const StreamInfo::StreamInfo& streamInfo() const PURE; + virtual StreamInfo::StreamInfo& streamInfo() PURE; }; /*** diff --git a/envoy/http/filter.h b/envoy/http/filter.h index 1caebab6a46c..f9cc5450c87b 100644 --- a/envoy/http/filter.h +++ b/envoy/http/filter.h @@ -896,7 +896,7 @@ class StreamFilterBase { /** * Stream decoder filter interface. */ -class StreamDecoderFilter : public StreamFilterBase { +class StreamDecoderFilter : public virtual StreamFilterBase { public: /** * Called with decoded headers, optionally indicating end of stream. @@ -1112,7 +1112,7 @@ class StreamEncoderFilterCallbacks : public virtual StreamFilterCallbacks { /** * Stream encoder filter interface. */ -class StreamEncoderFilter : public StreamFilterBase { +class StreamEncoderFilter : public virtual StreamFilterBase { public: /** * Called with supported 1xx headers. @@ -1200,6 +1200,9 @@ class HttpMatchingData { virtual const Network::ConnectionInfoProvider& connectionInfoProvider() const PURE; const StreamInfo::FilterState& filterState() const { return streamInfo().filterState(); } + const envoy::config::core::v3::Metadata& metadata() const { + return streamInfo().dynamicMetadata(); + } const Network::Address::Instance& localAddress() const { return *connectionInfoProvider().localAddress(); diff --git a/envoy/http/filter_factory.h b/envoy/http/filter_factory.h index 76f1162fcbd1..a53e8977a995 100644 --- a/envoy/http/filter_factory.h +++ b/envoy/http/filter_factory.h @@ -25,15 +25,12 @@ using FilterFactoryCb = std::function; @@ -195,6 +200,14 @@ class HttpServerPropertiesCacheManager { virtual HttpServerPropertiesCacheSharedPtr getCache(const envoy::config::core::v3::AlternateProtocolsCacheOptions& config, Event::Dispatcher& dispatcher) PURE; + + using CacheFn = std::function; + + /** + * Run the supplied function on each HttpServerPropertiesCache on this thread. + * @param cache_fn supplies the function to run. + */ + virtual void forEachThreadLocalCache(CacheFn cache_fn) PURE; }; using HttpServerPropertiesCacheManagerSharedPtr = std::shared_ptr; diff --git a/envoy/network/filter.h b/envoy/network/filter.h index dba97018b9ff..cf536e8ee06f 100644 --- a/envoy/network/filter.h +++ b/envoy/network/filter.h @@ -647,6 +647,217 @@ class UdpListenerFilterManager { using UdpListenerFilterFactoryCb = std::function; +/** + * Common interface for UdpSessionReadFilterCallbacks and UdpSessionWriteFilterCallbacks. + */ +class UdpSessionFilterCallbacks { +public: + virtual ~UdpSessionFilterCallbacks() = default; + + /** + * @return uint64_t the ID of the originating UDP session. + */ + virtual uint64_t sessionId() const PURE; + + /** + * @return StreamInfo for logging purposes. + */ + virtual StreamInfo::StreamInfo& streamInfo() PURE; + + /** + * Allows a filter to inject a datagram to successive filters in the session filter chain. + * The injected datagram will be iterated as a regular received datagram, and may also be + * stopped by further filters. This can be used, for example, to continue processing previously + * buffered datagrams by a filter after an asynchronous operation ended. + */ + virtual void injectDatagramToFilterChain(Network::UdpRecvData& data) PURE; +}; + +class UdpSessionReadFilterCallbacks : public UdpSessionFilterCallbacks { +public: + ~UdpSessionReadFilterCallbacks() override = default; + + /** + * If a read filter stopped filter iteration, continueFilterChain() can be called to continue the + * filter chain. It will have onNewSession() called if it was not previously called. + * @return false if the session is removed and no longer valid, otherwise returns true. + */ + virtual bool continueFilterChain() PURE; +}; + +class UdpSessionWriteFilterCallbacks : public UdpSessionFilterCallbacks {}; + +class UdpSessionFilterBase { +public: + virtual ~UdpSessionFilterBase() = default; + + /** + * This routine is called before the access log handlers' final log() is called. Filters can use + * this callback to enrich the data passed in to the log handlers. + */ + void onSessionComplete() { + if (!on_session_complete_already_called_) { + onSessionCompleteInternal(); + on_session_complete_already_called_ = true; + } + } + +protected: + /** + * This routine is called by onSessionComplete to enrich the data passed in to the log handlers. + */ + virtual void onSessionCompleteInternal() { ASSERT(!on_session_complete_already_called_); } + +private: + bool on_session_complete_already_called_{false}; +}; + +/** + * Return codes for read filter invocations. + */ +enum class UdpSessionReadFilterStatus { + // Continue to further session filters. + Continue, + // Stop executing further session filters. + StopIteration, +}; + +/** + * Session read filter interface. + */ +class UdpSessionReadFilter : public virtual UdpSessionFilterBase { +public: + ~UdpSessionReadFilter() override = default; + + /** + * Called when a new UDP session is first established. Filters should do one time long term + * processing that needs to be done when a session is established. Filter chain iteration + * can be stopped if needed. + * @return status used by the filter manager to manage further filter iteration. + */ + virtual UdpSessionReadFilterStatus onNewSession() PURE; + + /** + * Called when UDP datagram is read and matches the session that manages the filter. + * @param data supplies the read data which may be modified. + * @return status used by the filter manager to manage further filter iteration. + */ + virtual UdpSessionReadFilterStatus onData(Network::UdpRecvData& data) PURE; + + /** + * Initializes the read filter callbacks used to interact with the filter manager. It will be + * called by the filter manager a single time when the filter is first registered. + * + * IMPORTANT: No outbound networking or complex processing should be done in this function. + * That should be done in the context of onNewSession() if needed. + * + * @param callbacks supplies the callbacks. + */ + virtual void initializeReadFilterCallbacks(UdpSessionReadFilterCallbacks& callbacks) PURE; +}; + +using UdpSessionReadFilterSharedPtr = std::shared_ptr; + +/** + * Return codes for write filter invocations. + */ +enum class UdpSessionWriteFilterStatus { + // Continue to further session filters. + Continue, + // Stop executing further session filters. + StopIteration, +}; + +/** + * Session write filter interface. + */ +class UdpSessionWriteFilter : public virtual UdpSessionFilterBase { +public: + ~UdpSessionWriteFilter() override = default; + + /** + * Called when data is to be written on the UDP session. + * @param data supplies the buffer to be written which may be modified. + * @return status used by the filter manager to manage further filter iteration. + */ + virtual UdpSessionWriteFilterStatus onWrite(Network::UdpRecvData& data) PURE; + + /** + * Initializes the write filter callbacks used to interact with the filter manager. It will be + * called by the filter manager a single time when the filter is first registered. + * + * IMPORTANT: No outbound networking or complex processing should be done in this function. + * That should be done in the context of ReadFilter::onNewSession() if needed. + * + * @param callbacks supplies the callbacks. + */ + virtual void initializeWriteFilterCallbacks(UdpSessionWriteFilterCallbacks& callbacks) PURE; +}; + +using UdpSessionWriteFilterSharedPtr = std::shared_ptr; + +/** + * A combination read and write filter. This allows a single filter instance to cover + * both the read and write paths. + */ +class UdpSessionFilter : public virtual UdpSessionReadFilter, + public virtual UdpSessionWriteFilter {}; +using UdpSessionFilterSharedPtr = std::shared_ptr; + +/** + * These callbacks are provided by the UDP session manager to the factory so that the factory + * can * build the filter chain in an application specific way. + */ +class UdpSessionFilterChainFactoryCallbacks { +public: + virtual ~UdpSessionFilterChainFactoryCallbacks() = default; + + /** + * Add a read filter that is used when reading UDP session data. + * @param filter supplies the filter to add. + */ + virtual void addReadFilter(UdpSessionReadFilterSharedPtr filter) PURE; + + /** + * Add a write filter that is used when writing UDP session data. + * @param filter supplies the filter to add. + */ + virtual void addWriteFilter(UdpSessionWriteFilterSharedPtr filter) PURE; + + /** + * Add a bidirectional filter that is used when reading and writing UDP session data. + * @param filter supplies the filter to add. + */ + virtual void addFilter(UdpSessionFilterSharedPtr filter) PURE; +}; + +/** + * This function is used to wrap the creation of a UDP session filter chain for new sessions as they + * come in. Filter factories create the function at configuration initialization time, and then + * they are used at runtime. + * @param callbacks supplies the callbacks for the stream to install filters to. Typically the + * function will install a single filter, but it's technically possibly to install more than one + * if desired. + */ +using UdpSessionFilterFactoryCb = + std::function; + +/** + * A UdpSessionFilterChainFactory is used by a UDP session manager to create a UDP session filter + * chain when a new session is created. + */ +class UdpSessionFilterChainFactory { +public: + virtual ~UdpSessionFilterChainFactory() = default; + + /** + * Called when a new UDP session is created. + * @param callbacks supplies the "sink" that is used for actually creating the filter chain. @see + * UdpSessionFilterChainFactoryCallbacks. + */ + virtual void createFilterChain(UdpSessionFilterChainFactoryCallbacks& callbacks) const PURE; +}; + /** * Creates a chain of network filters for a new connection. */ diff --git a/envoy/router/router.h b/envoy/router/router.h index b6d23856649e..48ed169bcd40 100644 --- a/envoy/router/router.h +++ b/envoy/router/router.h @@ -900,6 +900,23 @@ class RouteEntry : public ResponseEntry { */ virtual const std::string& clusterName() const PURE; + /** + * Returns the final host value for the request, taking into account route-level mutations. + * + * The value returned is computed with the following logic in order: + * + * 1. If a host rewrite is configured for the route, it returns that value. + * 2. If a host rewrite header is specified, it attempts to use the value from that header. + * 3. If a host rewrite path regex is configured, it applies the regex to the request path and + * returns the result. + * 4. If none of the above apply, it returns the original host value from the request headers. + * + * @param headers The constant reference to the request headers. + * @note This function will not attempt to restore the port in the host value. If port information + * is required, it should be handled separately. + */ + virtual const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const PURE; + /** * Returns the HTTP status code to use when configured cluster is not found. * @return Http::Code to use when configured cluster is not found. @@ -1544,15 +1561,13 @@ class GenericUpstream { virtual void encodeTrailers(const Http::RequestTrailerMap& trailers) PURE; // TODO(vikaschoudhary16): Remove this api. - // This api is only used to enable half-close semantics on the upstream connection. - // This ideally should be done via calling connection.enableHalfClose() but since TcpProxy - // does not have access to the upstream connection, it is done via this api for now. + // This api is only used to enable TCP tunneling semantics in the upstream codec. + // TCP proxy extension uses this API when proxyingn TCP tunnel via HTTP CONNECT or POST. /** - * Enable half-close semantics on the upstream connection. Reading a remote half-close + * Enable TCP tunneling semantics on the upstream codec. Reading a remote half-close * will not fully close the connection. This is off by default. - * @param enabled Whether to set half-close semantics as enabled or disabled. */ - virtual void enableHalfClose() PURE; + virtual void enableTcpTunneling() PURE; /** * Enable/disable further data from this stream. */ diff --git a/envoy/server/filter_config.h b/envoy/server/filter_config.h index 099101409d91..3b09178513c1 100644 --- a/envoy/server/filter_config.h +++ b/envoy/server/filter_config.h @@ -76,6 +76,29 @@ class NamedUdpListenerFilterConfigFactory : public ListenerFilterConfigFactoryBa std::string category() const override { return "envoy.filters.udp_listener"; } }; +/** + * Implemented by each UDP session filter and registered via Registry::registerFactory or the + * convenience class RegisterFactory. + */ +class NamedUdpSessionFilterConfigFactory : public Envoy::Config::TypedFactory { +public: + ~NamedUdpSessionFilterConfigFactory() override = default; + + /** + * Create a particular UDP session filter factory implementation. If the implementation is + * unable to produce a factory with the provided parameters, it should throw an EnvoyException + * in the case of general error. The returned callback should always be initialized. + * @param config supplies the configuration for the filter + * @param context supplies the filter's context. + * @return UdpSessionFilterFactoryCb the factory creation function. + */ + virtual Network::UdpSessionFilterFactoryCb + createFilterFactoryFromProto(const Protobuf::Message& config, + Server::Configuration::FactoryContext& context) PURE; + + std::string category() const override { return "envoy.filters.udp.session"; } +}; + /** * Implemented by each QUIC listener filter and registered via Registry::registerFactory() * or the convenience class RegisterFactory. diff --git a/envoy/ssl/connection.h b/envoy/ssl/connection.h index 9cc4a77a25ac..cc4efd8ed242 100644 --- a/envoy/ssl/connection.h +++ b/envoy/ssl/connection.h @@ -60,6 +60,29 @@ class ConnectionInfo { **/ virtual const std::string& serialNumberPeerCertificate() const PURE; + /** + * @return absl::Span the SHA256 digests of all peer certificates. + * Returns an empty vector if there is no peer certificate which can happen in + * TLS (non mTLS) connections. + */ + virtual absl::Span sha256PeerCertificateChainDigests() const PURE; + + /** + * @return absl::Span the SHA1 digest of all peer certificates. + * Returns an empty vector if there is no peer certificate which can happen in + * TLS (non mTLS) connections. + */ + virtual absl::Span sha1PeerCertificateChainDigests() const PURE; + + /** + * @return absl::Span the serial numbers of all peer certificates. + * An empty vector indicates that there were no peer certificates which can happen + * in TLS (non mTLS) connections. + * A vector element with a "" value indicates that the certificate at that index in + * the cert chain did not have a serial number. + **/ + virtual absl::Span serialNumbersPeerCertificates() const PURE; + /** * @return std::string the issuer field of the peer certificate in RFC 2253 format. Returns "" if * there is no peer certificate, or no issuer. diff --git a/envoy/stream_info/stream_info.h b/envoy/stream_info/stream_info.h index f3b8232967d6..39ffd18cef6a 100644 --- a/envoy/stream_info/stream_info.h +++ b/envoy/stream_info/stream_info.h @@ -980,6 +980,23 @@ class StreamInfo { */ virtual bool shouldDrainConnectionUponCompletion() const PURE; + /** + * Set the parent for this StreamInfo. This is used to associate the + * stream info of an async client with the stream info of the downstream + * connection. + */ + virtual void setParentStreamInfo(const StreamInfo& parent_stream_info) PURE; + + /** + * Get the parent for this StreamInfo, if available. + */ + virtual OptRef parentStreamInfo() const PURE; + + /** + * Clear the parent for this StreamInfo. + */ + virtual void clearParentStreamInfo() PURE; + /** * Called if the connection decides to drain itself after serving this request. * @param should_drain true to close the connection once this stream has diff --git a/envoy/upstream/host_description.h b/envoy/upstream/host_description.h index 0a8d4815bbcd..069ddb5e46ed 100644 --- a/envoy/upstream/host_description.h +++ b/envoy/upstream/host_description.h @@ -204,6 +204,11 @@ class HostDescription { */ virtual const envoy::config::core::v3::Locality& locality() const PURE; + /** + * @return the metadata associated with the locality endpoints the host belongs to. + */ + virtual const MetadataConstSharedPtr localityMetadata() const PURE; + /** * @return the human readable name of the host's locality zone as a StatName. */ diff --git a/envoy/upstream/load_balancer.h b/envoy/upstream/load_balancer.h index c4b31ec27d2c..cc58b35e5ea3 100644 --- a/envoy/upstream/load_balancer.h +++ b/envoy/upstream/load_balancer.h @@ -243,6 +243,19 @@ class LoadBalancerConfig { }; using LoadBalancerConfigPtr = std::unique_ptr; +/** + * Context information passed to a load balancer factory to use when creating a load balancer. + */ +class LoadBalancerFactoryContext { +public: + virtual ~LoadBalancerFactoryContext() = default; + + /** + * @return Event::Dispatcher& the main thread dispatcher. + */ + virtual Event::Dispatcher& mainThreadDispatcher() PURE; +}; + /** * Factory config for load balancers. To support a load balancing policy of * LOAD_BALANCING_POLICY_CONFIG, at least one load balancer factory corresponding to a policy in @@ -273,12 +286,14 @@ class TypedLoadBalancerFactory : public Config::TypedFactory { * * @return LoadBalancerConfigPtr a new load balancer config. * + * @param lb_factory_context supplies the load balancer factory context. * @param config supplies the typed proto config of the load balancer. A dynamic_cast could * be performed on the config to the expected proto type. * @param visitor supplies the validation visitor that will be used to validate the embedded * Any proto message. */ - virtual LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, + virtual LoadBalancerConfigPtr loadConfig(LoadBalancerFactoryContext& lb_factory_context, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor& visitor) PURE; std::string category() const override { return "envoy.load_balancing_policies"; } diff --git a/envoy/upstream/upstream.h b/envoy/upstream/upstream.h index 45fd1a7cc58f..95a454abc799 100644 --- a/envoy/upstream/upstream.h +++ b/envoy/upstream/upstream.h @@ -1235,6 +1235,11 @@ class ClusterInfo : public Http::FilterChainFactory { virtual OptRef happyEyeballsConfig() const PURE; + /** + * @return Reference to the optional config for LRS endpoint metric reporting. + */ + virtual OptRef> lrsReportMetricNames() const PURE; + protected: /** * Invoked by extensionProtocolOptionsTyped. diff --git a/examples/BUILD b/examples/BUILD deleted file mode 100644 index 941806731c4d..000000000000 --- a/examples/BUILD +++ /dev/null @@ -1,114 +0,0 @@ -load("@rules_pkg//pkg:mappings.bzl", "pkg_files") -load("@rules_pkg//pkg:pkg.bzl", "pkg_tar") -load( - "//bazel:envoy_build_system.bzl", - "envoy_package", -) - -licenses(["notice"]) # Apache 2 - -envoy_package() - -filegroup( - name = "configs", - srcs = glob( - [ - "**/*.yaml", - ], - exclude = [ - "cache/ci-responses.yaml", - "cache/responses.yaml", - "dynamic-config-fs/**/*", - "jaeger-native-tracing/*", - "opentelemetry/otel-collector-config.yaml", - "**/*docker-compose*.yaml", - # Contrib extensions tested over in contrib. - "golang-http/*.yaml", - "golang-network/*.yaml", - "mysql/*", - "postgres/*", - "kafka/*.yaml", - ], - ), -) - -filegroup( - name = "contrib_configs", - srcs = glob( - [ - "golang-http/*.yaml", - "golang-network/*.yaml", - "mysql/*.yaml", - "postgres/*.yaml", - "kafka/*.yaml", - ], - exclude = [ - "**/*docker-compose*.yaml", - ], - ), -) - -filegroup( - name = "certs", - srcs = glob(["_extra_certs/*.pem"]), -) - -filegroup( - name = "docs_rst", - srcs = glob(["**/example.rst"]) + ["//examples/wasm-cc:example.rst"], -) - -pkg_files( - name = "examples_files", - srcs = [":files"], - prefix = "_include", - strip_prefix = "/examples", -) - -genrule( - name = "examples_docs", - srcs = [":docs_rst"], - outs = ["examples_docs.tar.gz"], - cmd = """ - TEMP=$$(mktemp -d) - for location in $(locations :docs_rst); do - example=$$(echo $$location | sed -e 's#^external/[^/]*/##' | cut -d/ -f2) - cp -a $$location "$${TEMP}/$${example}.rst" - echo " $${example}" >> "$${TEMP}/_toctree.rst" - done - echo ".. toctree::" > "$${TEMP}/toctree.rst" - echo " :maxdepth: 1" >> "$${TEMP}/toctree.rst" - echo "" >> "$${TEMP}/toctree.rst" - cat "$${TEMP}/_toctree.rst" | sort >> "$${TEMP}/toctree.rst" - rm "$${TEMP}/_toctree.rst" - tar czf $@ -C $${TEMP} . - """, -) - -filegroup( - name = "lua", - srcs = glob(["**/*.lua"]), -) - -filegroup( - name = "files", - srcs = glob( - [ - "**/*", - ], - exclude = [ - "**/node_modules/**", - "**/*.rst", - ], - ) + [ - "//examples/wasm-cc:files", - ], -) - -pkg_tar( - name = "docs", - srcs = [":examples_files"], - extension = "tar.gz", - package_dir = "start/sandboxes", - deps = [":examples_docs"], -) diff --git a/examples/DEVELOPER.md b/examples/DEVELOPER.md deleted file mode 100644 index f89bdfb37b95..000000000000 --- a/examples/DEVELOPER.md +++ /dev/null @@ -1,323 +0,0 @@ -# Adding a sandbox example - -## Add a `verify.sh` test to your sandbox - -Sandboxes are tested as part of the continuous integration process, which expects -each sandbox to have a `verify.sh` script containing tests for the example. - -### Basic layout of the `verify.sh` script - -At a minimum the `verify.sh` script should include the necessary parts to start -and stop your sandbox. - -Given a sandbox with a single `docker` composition, adding the following -to `verify.sh` will test that the sandbox can be started and stopped. - -```bash -#!/bin/bash -e - -export NAME=example-sandbox - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# add example tests here... - -``` - -The `$NAME` variable is used for logging when testing the example, and will -often be the same as the directory name. - -### Log before running each test - -There is a utility function `run_log` that can be used to indicate in test logs what -is being executed and why, for example: - -```bash -run_log "Checking foo.txt was created" -ls foo.txt - -run_log "Checking bar.txt was created" -ls bar.txt -``` - -### Add tests reflecting the documented examples - -The tests should follow the steps laid out in the documentation. - -For example, if the documentation provides a series of `bash` commands to execute, add these in order to `verify.sh`. - -You may wish to grep the responses, or check return codes to ensure the commands respond as expected. - -Likewise, if the documentation asks the user to browse to a page - for example http://localhost:8000 - -then you should add a test to ensure that the given URL responds as expected. - -If an example web page is also expected to make further JavaScript `HTTP` requests in order to function, then add -tests for requests that mimick this interaction. - -A number of utility functions have been added to simplify browser testing. - -#### Utility functions: `responds_with` - -The `responds_with` function can be used to ensure a request to a given URL responds with -expected `HTTP` content. - -It follows the form `responds_with []` - -For example, a simple `GET` request: - -```bash -responds_with \ - "Hello, world" \ - http://localhost:8000 -``` - -This is a more complicated example that uses an `HTTPS` `POST` request and sends some -additional headers: - -```bash -responds_with \ - "Hello, postie" \ - https://localhost:8000/some-endpoint \ - -k \ - -X POST \ - -d 'data=hello,rcpt=service' \ - -H 'Origin: https://example-service.com' -``` - -#### Utility functions: `responds_without` - -You can also check that a request *does not* respond with given `HTTP` content: - -```bash -responds_without \ - "Anything unexpected" \ - "http://localhost:8000" -``` - -`responds_without` can accept additional curl arguments like `responds_with` - -#### Utility functions: `responds_with_header` - -You can check that a request responds with an expected header as follows: - -```bash -responds_with_header \ - "HTTP/1.1 403 Forbidden" \ - "http://localhost:8000/?name=notdown" -``` - -`responds_with_header` can accept additional curl arguments like `responds_with` - -#### Utility functions: `responds_without_header` - -You can also check that a request *does not* respond with a given header: - -```bash -responds_without_header \ - "X-Secret: treasure" \ - "http://localhost:8000" -``` - -`responds_without_header` can accept additional curl arguments like `responds_with` - -#### Utility functions: `wait_for` - -You can wait for some amount of time (specified in seconds) for a command to return `0`. - -The following example will wait for 20 seconds for a service ``my-service`` to become healthy. - -```bash -wait_for 20 sh -c "docker-compose ps my-service | grep healthy | grep -v unhealthy" -``` - -### Slow starting `docker` compositions - -Unless your example provides a way for ensuring that all containers are healthy by -the time `docker-compose up -d` returns, you may need to add a `DELAY` before running -the steps in your `verify.sh` - -For example, to wait 10 seconds after `docker-compose up -d` has been called, set the -following: - -```bash -#!/bin/bash -e - -export NAME=example-sandbox -export DELAY=10 - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# add example tests here... -``` - -### Examples with multiple `docker` compositions - -For your example to work it may need more than one `docker` composition to be run. - -You can set where to find the `docker-compose.yaml` files with the `PATHS` argument. - -By default `PATHS=.`, but you can change this to a comma-separated list of paths. - -For example a sandbox containing `frontend/docker-compose.yaml` and `backend/docker-compose.yaml`, -might use a `verify.sh` with: - -```bash -#!/bin/bash -e - -export NAME=example-sandbox -export PATHS=frontend,backend - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# add example tests here... -``` - -### Bringing stacks up manually - -You may need to bring up the stack manually, in order to run some steps beforehand. - -Sourcing `verify-common.sh` will always leave you in the sandbox directory, and from there -you can use the `bring_up_example` function. - -For example: - -```bash -#!/bin/bash -e - -export NAME=example-sandbox -export MANUAL=true - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Creating bar.txt before starting containers" -echo foo > bar.txt - -bring_up_example - -# add example tests here... -``` - -If your sandbox has multiple compositions, and uses the `$PATHS` env var described above, -`bring_up_example` will bring all of your compositions up. - -### Additional arguments to `docker-compose up -d` - -If you need to pass additional arguments to compose you can set the `UPARGS` -env var. - -For example, to scale a composition with a service named `http_service`, you -should add the following: - -```bash -#!/bin/bash -e - -export NAME=example-sandbox -export UPARGS="--scale http_service=2" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# add example tests here... -``` - -### Running commands inside `docker` containers - -If your example asks the user to run commands inside containers, you can -mimick this using `docker-compose exec -T`. The `-T` flag is necessary as the -tests do not have access to a `tty` in the CI pipeline. - -### Note on permissions and configuration - -The sandbox tests are run with a `umask` setting of `027` to ensure they will run in environments -where this is the case. - -As the Envoy containers run as non-root, it is essential that any configurations required -by the daemon are included in the relevant example `Dockerfile` rather than mounted in -any `docker-compose.yaml` files. - -The Docker recipe should also ensure that added configurations are world-readable. - -For example, with an added configuration file named `front-envoy.yaml`, you should add -the following in the Docker recipe: - -``` -RUN chmod go+r /etc/front-envoy.yaml -``` - -### Additional `pip` dependencies - -Pip dependencies should be added to a `requirements.in` file, and compiled with `pip-compile`. - -Please see existing examples for further information. - -The `requirements.txt` will also need to be added to `.github/dependabot.yaml`. - -### Shared Docker images and service definitions - -There are shared `Dockerfile` resources available for use in building an example. - -Please see the `examples/shared` folder. - -## Sandbox configuration tests - -Example configuration files are tested to ensure they are valid and well-formed, and do -not contain deprecated features. - -### Exclude configs from example configuration tests - -The CI script searches for all files in the examples folders with a `yaml` or `lua` extension. - -These files are bundled into a test and the `yaml` files are used to try to start an Envoy server. - -If your example includes `yaml` files that are either not Envoy configuration, or for some reason -cannot be tested in this way, you should add the files to the `exclude` list in the `filegroup.srcs` -section of the `examples/BUILD` file. - -The `exclude` patterns are evaluated as `globs` in the context of the `examples` folder. - - -## Verifying your sandbox - -Once you have built your sandbox, and added the `verify.sh` script you can run it directly in the -sandbox folder. - -For example: - -``` -cd examples/example-sandbox -./verify.sh - -``` - -You should see the docker composition brought up, your tests run, and the composition brought down again. - -The script should exit with `0` for the tests to pass. - - -## Verifying multiple/all sandboxes - -In continuous integration, all of the sandboxes are checked using the `ci/verify-examples.sh`. - -This can also be called with a filter argument, which is a `glob` evaluated in the context of the `examples` folder. - -For example, to run all sandboxes with names beginning `jaeger`: - -``` -./ci/verify-examples.sh jaeger* -``` - ---- - -**NOTE** - -You can use this script locally to test the sandboxes on your platform, but you should be aware that it requires -a lot of resources as it downloads and builds many Docker images, and then runs them in turn. - ---- - -One way to run the tests in an isolated environment is to mount the `envoy` source into a `docker-in-docker` container -or similar, and then run the script from inside that container. diff --git a/examples/_extra_certs/README.md b/examples/_extra_certs/README.md deleted file mode 100644 index 3e4b69997626..000000000000 --- a/examples/_extra_certs/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Extra certificates for config validation testing -================================================ - -This folder contains certs that are referenced in the sandbox examples, that end users are -expected to create themselves. - -In order to test the related configs we need to provide the certs to CI. diff --git a/examples/_extra_certs/domain1.crt.pem b/examples/_extra_certs/domain1.crt.pem deleted file mode 100644 index 33be12e8b02c..000000000000 --- a/examples/_extra_certs/domain1.crt.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDhDCCAmygAwIBAgITAJlvbEs3wtayr3rx+TyuBtu0mTANBgkqhkiG9w0BAQsF -ADBSMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExGDAWBgNVBAoMD015RXhhbXBs -ZSwgSW5jLjEcMBoGA1UEAwwTZG9tYWluMS5leGFtcGxlLmNvbTAeFw0yMDExMTIx -MTA3MDdaFw0yMTExMTIxMTA3MDdaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD -QTEYMBYGA1UECgwPTXlFeGFtcGxlLCBJbmMuMRwwGgYDVQQDDBNkb21haW4xLmV4 -YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA15Q63skf -pc5o2mhBE0dOcJaTqLS+nmIO5jK8QUKctpbOQz2p7j9zi9ZUh++4N84yjF56GQEw -/KqPvPHNA/tJKpkDugWHq4IFPU+o1k2AJKLVEvN3wXpbiae77eqgUCg0aS6kWDaT -LrCie/laxnSpnfRGDo1xsLRqNLzZxF3CPvA/WbgpR1JXYUAnoXZGHISrnXLzyI1O -DaDdDoi8Nn54neZ9jXtkeDWfuO5NkXK/U1dNnCez9a7EGO+h8ZF0Uc12UqPiX86L -frK0v25n94lPTGq5SOgswATMSOfN6g4pGaUFofZIyenHamUngzqm55M+/tMeiaF7 -Pwf4wcTyXEaXcQIDAQABo1MwUTAdBgNVHQ4EFgQUTSuIMFANakAWSPIUiqdMUrFq -66YwHwYDVR0jBBgwFoAUTSuIMFANakAWSPIUiqdMUrFq66YwDwYDVR0TAQH/BAUw -AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAdbdIBKAomEsGtcuWWc8vI4r0l+AMegGK -yg86byKm9WRHtpYnO+iZ+SopTLTFhgLsGfEMoN+HGeUIexUvwDzb384EJ4kLPr3E -Yqt5uNz9YMuFpkhuFTL+V5RczcPKfir5hzAgvAtj6eaRf9WPlObF+Rr0t8pJZG0k -9dEtBqE87XVUDvj6waMCpTFxwv22E/xjRJ5nSDjfk9y8LDpIF5SOunncVMRVfcjg -Qp0Q9KpZpbxXFMYVBfMxp4Z/KQd0W5nVWZlwg/D03n0IkS0e8irUyrerFLdOTwxf -G5M/n/VeCwC2GPlT8Eo/3BUa+SeX2iHl93/osqfWNQAY3riaN0y+FA== ------END CERTIFICATE----- diff --git a/examples/_extra_certs/domain1.key.pem b/examples/_extra_certs/domain1.key.pem deleted file mode 100644 index eefcca26453f..000000000000 --- a/examples/_extra_certs/domain1.key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXlDreyR+lzmja -aEETR05wlpOotL6eYg7mMrxBQpy2ls5DPanuP3OL1lSH77g3zjKMXnoZATD8qo+8 -8c0D+0kqmQO6BYerggU9T6jWTYAkotUS83fBeluJp7vt6qBQKDRpLqRYNpMusKJ7 -+VrGdKmd9EYOjXGwtGo0vNnEXcI+8D9ZuClHUldhQCehdkYchKudcvPIjU4NoN0O -iLw2fnid5n2Ne2R4NZ+47k2Rcr9TV02cJ7P1rsQY76HxkXRRzXZSo+Jfzot+srS/ -bmf3iU9MarlI6CzABMxI583qDikZpQWh9kjJ6cdqZSeDOqbnkz7+0x6JoXs/B/jB -xPJcRpdxAgMBAAECggEBALvIi+tKaH3mqaEuVRk08NfT4jV/k9ek9POCWEfEfXvz -KyKZUS+OJ9k0TpfGscIypAdvuI2VYxWEgQaF3h7MwfQQK5XbgU1dSbEZdamPAsNm -75G9cKChM6FZ8bKRwSlxjA3fKhsJFvYBuNei4naiYqmLgYbloJXa4fSkWFDblvt4 -cmsP9iEZL7tBJ4bIGmugpPR83PPlfu/EQY2w8T+Rw8/JAXDd80V1egCucYpwOx94 -esXVpWzTA3xZyPTlQrFmOe9NEb2C5oqOx1s/zmfQpytKPjF7YojnHnYeHrDL5Y+j -sVP753celaYncWoANfAyV4FOxEsOa1OCKbF5OOuWPI0CgYEA/KyTK4NyRHqXrhuO -J/rRDhhZBomP4LkY2uTMdOH+n0hvy0m5eV5+88CQF6atSfKQ8h+zbhJVNeVilZDK -NhjAEm+x2vME41Wp1vqsALpPtuGFQm3EcwKDvTgyvm04X2RfZSZ4MT0993M/g07u -x+VQiZu127PjcNibDXXoDwM5p/MCgYEA2mqoRnTr/DCrO8u678ccv8MYHhh0ISOs -Tbmh83qROWehdoB6kRQ/i+kefbL6Rw0bY5+3rlvQ+3B3MvVoYLWUWuyhtYK2pt3i -R071WPCuR3PIVOEK+wuHi85peiGSHxfEDiUb3AvNnd8dZGBFnHe8mZObccc7b4uy -jT4VLJ56IAsCgYEAlg3GuKivS4uiWHt0yLljPYOoGwHGuCY0ZIpMAX3UwLM78PYv -d6xuqENLT0Bk2O18ts2suUmZ4RAAo+IAtG+uYUSD0wtPc9KDsm/bhfMfM/RqNzEI -4WQ06EJfoEcsmzn4jRFzf4pnKnT+2vQdSgkc8xvNvFPwVivMqQnEbmXz75ECgYBr -BTfOzhuTRoWglwLR2k5L59w5YuIEGuaibwLbuoLODekfl3R3AeThOSinjrrzdYim -F+x4kqSjj0fYwEaUnGRE6Q2TUqkMukvVhOrS2ZuLhz/x1xL6T3vrFQi5vxlKAusd -wzETcPUfFePg+wsgz8qptZnE9ko5LcofSvw1ELHmYQKBgBfT1GtRlYCEMbuSJY20 -AtoOg5vN2b6s2nqQGff7J8UOywPDk9hyboL4ByS9Udemap0USisGAZiEfq+VbA+2 -lPhV/gmBFDidCCYRXKi6qfcDG9ssJ5Gylg/8XaaMKAQ7vp73sQYTDlcgUcPx90ue -GMITMZWQr8Qs/u9zl22tnxAb ------END PRIVATE KEY----- diff --git a/examples/_extra_certs/domain2.crt.pem b/examples/_extra_certs/domain2.crt.pem deleted file mode 100644 index 9f983682ae6b..000000000000 --- a/examples/_extra_certs/domain2.crt.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDhTCCAm2gAwIBAgIUXBZV/SLVGAdsb1mJrpuahYegPLEwDQYJKoZIhvcNAQEL -BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRgwFgYDVQQKDA9NeUV4YW1w -bGUsIEluYy4xHDAaBgNVBAMME2RvbWFpbjIuZXhhbXBsZS5jb20wHhcNMjAxMTEy -MTEwNzA3WhcNMjExMTEyMTEwNzA3WjBSMQswCQYDVQQGEwJVUzELMAkGA1UECAwC -Q0ExGDAWBgNVBAoMD015RXhhbXBsZSwgSW5jLjEcMBoGA1UEAwwTZG9tYWluMi5l -eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJfPje1r -nUfVnHobHRKReisGdGWHQhngJlp3II7sPk0vRuvOLsyLp0AKA/pS0isW1WFUh+Kz -BpOVrU/LPqi1ZW38mzCgGr91fc999vtsZyXOCEh7Vi3UVfzVtSNwnijlG3wovjGK -DqLlne03/lPFT1x9coIy7XvA1ZICfX8EfP5ajt60+UWYXAKN2FLas9K+3lzzbHx5 -F/iI134A695ozLNHT1qe+IOA6NwW5LoTwzoHRVMoJz2cvSRr0vCVkt0IvO5ARyyr -400Nx0vKkxhf0Z+yXGSowWVN8VtSPiRSeC4vGmPRl6O6XoiPwjus2jlXrJifcIyg -hNDrOQnYbYK5dA8CAwEAAaNTMFEwHQYDVR0OBBYEFIQfS5xxWYX7pWgc59p+h6y8 -sQMFMB8GA1UdIwQYMBaAFIQfS5xxWYX7pWgc59p+h6y8sQMFMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIHDjt+wxYuOJkI8VncVR6VpGy9hqntd -rnNxupReenhocPN/QIl1TQva/gGq4gz1vNWhHz1B5bxPoyPESed5+QQvJMo3/5Ub -OyDIKwspwRy6PUoyJDjhC/z7B2FhZPmxVmbHfhL0wiQjI7j/u+/c8Jq9YDr8ZsZs -whXjvSOl9+I0xWZFRN0O+cFszTnoucmLRdFVl648ghUlW3m6/YNWF+mLucleZVt3 -wFUKGwq88Z4sU6kqcXXG4GykZYmSwB3BmaaamQKq06v+k9Qjrj5gJD8S1Ygznc6/ -Z+ZzAb/FfHXHV6QbY5/35wVFO3OMk6NHy9oLZrfPxBn/C5brUz+dXnI= ------END CERTIFICATE----- diff --git a/examples/_extra_certs/domain2.key.pem b/examples/_extra_certs/domain2.key.pem deleted file mode 100644 index 12602841945f..000000000000 --- a/examples/_extra_certs/domain2.key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXz43ta51H1Zx6 -Gx0SkXorBnRlh0IZ4CZadyCO7D5NL0brzi7Mi6dACgP6UtIrFtVhVIfiswaTla1P -yz6otWVt/JswoBq/dX3Pffb7bGclzghIe1Yt1FX81bUjcJ4o5Rt8KL4xig6i5Z3t -N/5TxU9cfXKCMu17wNWSAn1/BHz+Wo7etPlFmFwCjdhS2rPSvt5c82x8eRf4iNd+ -AOveaMyzR09anviDgOjcFuS6E8M6B0VTKCc9nL0ka9LwlZLdCLzuQEcsq+NNDcdL -ypMYX9GfslxkqMFlTfFbUj4kUnguLxpj0Zejul6Ij8I7rNo5V6yYn3CMoITQ6zkJ -2G2CuXQPAgMBAAECggEAJ089Rv8YqOMtM4kVzBsTcVSoiyms+hpKlB5ItfmCYGYf -jSvEfn6i/jgZs5YCidnNwvgqf48v4sNdL05HmVPvQb2pSbwLcQwxWasaaxw00Vs6 -VdpqBE/5PBDyaIzex2Qb69h490byZ0fhzu0y0+pBlId/QSuCxwq1wqsWZ+93ljzi -rDDoPSWcty0R3QWrMUmbihi6i8v8fbFz174jxGH1TRJ0+a9IuGZ9Yap1mSg9YC/0 -oM20lsvmQvczXYdJMUhg0CYJ3weThO9pK4fnDa7pvkBgxgOTOY2TZh3PUs7DmYa7 -YCE5xp8CviKZywaAqvowjfdWj8yCU5ZFzN4LdDmhMQKBgQDHL/dUg61+viWR7GyD -Kb9E9FjktwSu52Ec1jfcjFe8UkRJa7JiruagVXuekAVvA+R7ZifSb0Yfs1QaHwA3 -NPvVpwb3omW02gfbXR9AJ/eEJfgkcliPrJsL0QqbLu+w+5CFaj/iCN5SxE822WLx -3dGNDOrQEr0A+K3Hmj5SCtCmbQKBgQDDHEwxzjq6jw2n+K0ArIvpXa1/hteT6h1q -7Qcg9nEaSiVbYAfp+1qgQqoCMe7aSNJe/RuGP59mwlIgt1rn+QFgb8K9IoZYvb4N -jwLmuOx1tLWtbRLHHFdYA14XlwKOl79NwjJPepCZIU8eOzaDLBUUeH0DkgJgwSZ2 -TnJOmp6m6wKBgHL0tNpa0INoPAiWmR2tt0yVdMQy+An1UW+yFjU77dqq4+w3spEP -fdyk2R5u4iPq7C9niq4BOEhNV8lngNlbw8fPiM7cM7SHbKdmfAWry0bCHw7xyzjI -Fgdg0q0zDnRnC0ZkRpAuLBk6YLk4BsmuCiVMgiwp1Fi+LJUY6MSypy6VAoGAUFun -RhwaNBwXE8dn+Y8XUNY0TwHKaDFUTGWzOfBGRP2kxS2YFNZhTQAn5R+LsHutqVG1 -tGUf0cLW8IKT/lagKofdPOirTIFZdVwhZcVkHlZ/PR5fTYJutuEsL6sScogtUmlZ -L0LbqzX80AazPPM6+2NkmcPZFuB2ZuOIULd+AGECgYBt40PiCf1WmAQK9J3pylOD -s7kWwzapIAKf92JBJmo5sOushYsPXAnqUJaZERpBBCmsdtYyjQV8VYxg/CrU5CkE -0zdFmFcfw7swwaE+aJLwueV1qR7lKi89DYZ9OFI+Z0JoekQc/TPeJLg1MctK76qA -OMswum0oXiu/zZJGGtCegg== ------END PRIVATE KEY----- diff --git a/examples/_extra_certs/domain3.crt.pem b/examples/_extra_certs/domain3.crt.pem deleted file mode 100644 index fdfbd07e9321..000000000000 --- a/examples/_extra_certs/domain3.crt.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDhTCCAm2gAwIBAgIUI/iTc/yKhX+HkiDCKAuCa25fxQwwDQYJKoZIhvcNAQEL -BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRgwFgYDVQQKDA9NeUV4YW1w -bGUsIEluYy4xHDAaBgNVBAMME2RvbWFpbjMuZXhhbXBsZS5jb20wHhcNMjAxMTEy -MTEwNzA3WhcNMjExMTEyMTEwNzA3WjBSMQswCQYDVQQGEwJVUzELMAkGA1UECAwC -Q0ExGDAWBgNVBAoMD015RXhhbXBsZSwgSW5jLjEcMBoGA1UEAwwTZG9tYWluMy5l -eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOO0k18 -6k3164UpYGVOC1oj8jbmdZeeg57mkamYE9CUk0W9KKgHOCSNMZXUxPtnqtqJgJ92 -ccawTe0WrbOKQA3ARK7WePbX3HepJfTFZgCC5d5njRPDfIgsk4MP89nc2p8qO5Vv -SvCTae8/ykTyfz5fKwaGMYwvrSGUpuhFD8OFMOAsvnoIXZd+ixLkDATupP/IaV0a -6tHs6BnC3vxn+baC30fuHKErfOh7Jlo3FDqXNMwfes6MJ7/u8odeFfuGOaaO4eRT -EAhy4VQBJkCtS3yCFEv3kCRXjmgEBDSQ9jDjtnykOqViO5euibeKxnz+7xjRWVGY -bT5Z+s6eUHkiraMCAwEAAaNTMFEwHQYDVR0OBBYEFDVYD/F+NzsKgfYsRM6XfMuB -qXmqMB8GA1UdIwQYMBaAFDVYD/F+NzsKgfYsRM6XfMuBqXmqMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQELBQADggEBABwiF5AVDmQTLYE4wuHxq245qOj/vKfi -1L2lNgZ7G2Luobbvli2SQo7g8UYMSrwNF3Y1TDoEryeYMKYr2udb8WvdzhlL3z/J -a/qBElwWsATnpRfBAqxeWkx0x0E0C4nrjXM7PbAEjvEZ2AQKc5zmvii1Ek4h/+Sa -h2+Tmm5zg0Lo410CqujRmGtHU2AtkqguOhNrvJcRxEH4iLDB87WfUlLW6JrN+CLB -qIxkyLlhMUNMa200mpsfwQQRdImTjdn+VgpFR9BeZYU2gPZxqdxKcyrGfYXim1oJ -dC34TKistMWFs0C3l+Xs7unqSkqk5s1Nkdh6vnMF39PkwFoVP3Nn2wY= ------END CERTIFICATE----- diff --git a/examples/_extra_certs/domain3.key.pem b/examples/_extra_certs/domain3.key.pem deleted file mode 100644 index 84f259bd0a8a..000000000000 --- a/examples/_extra_certs/domain3.key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDDjtJNfOpN9euF -KWBlTgtaI/I25nWXnoOe5pGpmBPQlJNFvSioBzgkjTGV1MT7Z6raiYCfdnHGsE3t -Fq2zikANwESu1nj219x3qSX0xWYAguXeZ40Tw3yILJODD/PZ3NqfKjuVb0rwk2nv -P8pE8n8+XysGhjGML60hlKboRQ/DhTDgLL56CF2XfosS5AwE7qT/yGldGurR7OgZ -wt78Z/m2gt9H7hyhK3zoeyZaNxQ6lzTMH3rOjCe/7vKHXhX7hjmmjuHkUxAIcuFU -ASZArUt8ghRL95AkV45oBAQ0kPYw47Z8pDqlYjuXrom3isZ8/u8Y0VlRmG0+WfrO -nlB5Iq2jAgMBAAECggEBALe2MUzIP9kTYLlNIJiq07FPuZjnsarJKD8bvdWD34GA -QkYuqMYJWi3EUsO+CXtgbTo2GJY1kDcmo15Kgs3636fLavqQ0zyZlyz2w4iJ9QQf -9FCWGQtrB09qCP4D+4I8n0kNRMJithUBd3BiDePtp6nxf5r2cA+RLmUwoAft8Rws -GoZF5vm93iHF29H/nbP7KNTyBAoRq95y+SiXvcLOb9pN5IwAiqkAcVF8YpUCqsQL -PRTJZupSRU3Cg0Asq9nvqxeTBrySeOkoRid9b/5/MKP2CXNkGoOl7TCiHJ1SFYCd -waN+516Nd6Hu8WpH7n3eqcc/JhmP7jLv3vqLYAWpJ/ECgYEA9XigdnEiGFuP/SAE -l8InIGfNxGegEb9AMifZdir4lI1BKC+Ke84TD0V5tgHS5zsk8SOAIERHrclOTtHR -WPEx+GDrsukl3QDisdFE6sU1ktZ9S0uim9hYGaAtxME99U3EhDTBLApNyhxe2REC -yZoCuObqz7OVCu+SZ6/etw5mk+kCgYEAy/IgXJxCD3ais1Jy0DOfrzSExXulOi4X -+EWtMNcBkcYxE0Jl1mpsgd7GZNnJCf8ThajetREPFYzMCYiI6KOtOJBi+Bil6hpI -N2U29LD/dxIotHzdIau4ESFODJdgP2agzFx72JDKEBxGsuc7x5bd7P8hex+XURTW -KVuawJPXOasCgYEAoYXCcK149fYqBTGwU/vZqyUi7P4TAhqKr3YxTeRwta9NFJhT -06uCNyZMNEt279inMlVd1d2YHO69rHe7/X6YlwuPjKaF16rhgIhnhORHoFurDoSy -d0IglpwkAbf2gRevHB9qjQQqs7d/Ye4jm2zQJcMs94b/p7aE6915+5JqRSECgYAo -uC4n73btGXXAsfyEf1oppCXCPD6wEBXvFxJORw9kKJsRylcE6XjCsVURO759BXXD -YQUeR8qoNdVjLeSP9mYWfhWUjW9K/3ZdwRKo5lILVw/TgX6xQ1Tb7rdjojGwVvBR -/UEo6ze84bhn7e0sm32x3Pq1V4hhwvRDi6upOZtmQwKBgQDbjiPYdqKkbrC7YFsH -4m9VenSmnOppugcYU5h3zLORERfuTBT4cT2TEZT4zlz1vUZFjoQ5ML97xSGeCKzN -0Y0uh6zRgoy2zAQzwmtrNi80GuFEv1CJq7qxzz3aDU2Y/qYFmnl2cTwLNC+MxpbJ -lpvH9Ufkaj4vu/Iuw/Dnc2BPQg== ------END PRIVATE KEY----- diff --git a/examples/brotli/README.md b/examples/brotli/README.md deleted file mode 100644 index 575b73903e7b..000000000000 --- a/examples/brotli/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/brotli.html) diff --git a/examples/brotli/docker-compose.yaml b/examples/brotli/docker-compose.yaml deleted file mode 100644 index 78ec88551f44..000000000000 --- a/examples/brotli/docker-compose.yaml +++ /dev/null @@ -1,21 +0,0 @@ -services: - - envoy-stats: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-admin - args: - ENVOY_ADMIN_PORT: 9901 - depends_on: - service: - condition: service_healthy - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_STATS0:-9901}:9901" - - "${PORT_STATS1:-9902}:9902" - - service: - build: - context: ../shared/python - target: aiohttp-data-service diff --git a/examples/brotli/envoy.yaml b/examples/brotli/envoy.yaml deleted file mode 100644 index 703af847b73b..000000000000 --- a/examples/brotli/envoy.yaml +++ /dev/null @@ -1,238 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - application/json - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.brotli.compressor.v3.Brotli - window_bits: 10 - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/brotli-key.pem -out a/brotli-crt.pem -days 3650 -nodes -subj '/CN=brotli' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - address: - socket_address: - address: 0.0.0.0 - port_value: 9902 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/stats/prometheus" - route: - cluster: envoy-stats - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - text/plain - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.brotli.compressor.v3.Brotli - window_bits: 10 - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/brotli.pem -out a/brotli-crt.pem -days 3650 -nodes -subj '/CN=brotli' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: envoy-stats - connect_timeout: 0.25s - type: STATIC - load_assignment: - cluster_name: envoy-stats - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 9901 - - name: service - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 9901 diff --git a/examples/brotli/example.rst b/examples/brotli/example.rst deleted file mode 100644 index 62e9e0246b16..000000000000 --- a/examples/brotli/example.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. _install_sandboxes_brotli: - -Brotli -====== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -By enabling compression in Envoy you can save some network bandwidth, at the expense of increased processor usage. - -Envoy supports compression and decompression for both requests and responses. - -This sandbox provides an example of response compression served over ``HTTPS``. - -The sandbox covers two scenarios: - -- compression of files from an upstream server -- compression of Envoy's own statistics - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/brotli`` directory and bring up the docker composition. - -.. code-block:: console - - $ pwd - envoy/examples/brotli - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - brotli_envoy-stats_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp, 0.0.0.0:9901->9901/tcp,:::9901->9901/tcp, 0.0.0.0:9902->9902/tcp,:::9902->9902/tcp - brotli_service_1 python3 /code/service.py Up (healthy) - -Step 2: Test Envoy’s compression of upstream files -************************************************** - -The sandbox is configured with two endpoints on port ``10000`` for serving upstream files: - -- ``/file.txt`` -- ``/file.json`` - -Only ``/file.json`` is configured to be compressed. - -Use ``curl`` to check that the response from requesting ``file.json`` contains the ``content-encoding: br`` header. - -You will need to add an ``accept-encoding: br`` request header. - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: br" https://localhost:10000/file.json | grep "content-encoding" - content-encoding: br - -As only files with a content-type of ``application/json`` are configured to be compressed, the response from requesting ``file.txt`` should not contain the ``content-encoding: br`` header, and the file will not be compressed: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: br" https://localhost:10000/file.txt | grep "content-encoding" - -Step 3: Test compression of Envoy’s statistics -********************************************** - -The sandbox is configured with two ports serving Envoy’s admin and statistics interface: - -- ``9901`` exposes the standard admin interface without tls -- ``9902`` exposes a compressed version of the admin interface with tls - -Use ``curl`` to make a request for uncompressed statistics on port ``9901``, it should not contain the ``content-encoding`` header in the response: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: br" http://localhost:9901/stats/prometheus | grep "content-encoding" - -Now, use ``curl`` to make a request for the compressed statistics: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: br" https://localhost:9902/stats/prometheus | grep "content-encoding" - content-encoding: br - -.. seealso:: - :ref:`Brotli API ` - API and configuration reference for Envoy's brotli compression. - - :ref:`Compression configuration ` - Reference documentation for Envoy's compressor filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/brotli/verify.sh b/examples/brotli/verify.sh deleted file mode 100755 index 7aca2b3e590a..000000000000 --- a/examples/brotli/verify.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -e - -export NAME=brotli -export PORT_PROXY="${BROTLI_PORT_PROXY:-10200}" -export PORT_STATS0="${BROTLI_PORT_PROXY:-10201}" -export PORT_STATS1="${BROTLI_PORT_PROXY:-10202}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -wait_for 10 bash -c "\ - responds_with_header \ - 'content-encoding: br' \ - https://localhost:${PORT_PROXY}/file.json -ki -H 'Accept-Encoding: br'" - -run_log "Test service: localhost:${PORT_PROXY}/file.json with compression" -responds_with_header \ - "content-encoding: br" \ - "https://localhost:${PORT_PROXY}/file.json" \ - -ki -H "Accept-Encoding: br" - -run_log "Test service: localhost:${PORT_PROXY}/file.txt without compression" -responds_without_header \ - "content-encoding: br" \ - "https://localhost:${PORT_PROXY}/file.txt" \ - -ki -H "Accept-Encoding: br" - -run_log "Test service: localhost:${PORT_STATS0}/stats/prometheus without compression" -responds_without_header \ - "content-encoding: br" \ - "http://localhost:${PORT_STATS0}/stats/prometheus" \ - -ki -H "Accept-Encoding: br" - -run_log "Test service: localhost:${PORT_STATS1}/stats/prometheus with compression" -responds_with_header \ - "content-encoding: br" \ - "https://localhost:${PORT_STATS1}/stats/prometheus" \ - -ki -H "Accept-Encoding: br" diff --git a/examples/cache/README.md b/examples/cache/README.md deleted file mode 100644 index 4ef02a1844d1..000000000000 --- a/examples/cache/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/cache.html) diff --git a/examples/cache/ci-responses.yaml b/examples/cache/ci-responses.yaml deleted file mode 100644 index be571a8338c7..000000000000 --- a/examples/cache/ci-responses.yaml +++ /dev/null @@ -1,13 +0,0 @@ -valid-for-minute: - body: This response will stay fresh for one minute - headers: - cache-control: max-age=4 - custom-header: any value -private: - body: This is a private response, it will not be cached by Envoy - headers: - cache-control: private -no-cache: - body: This response can be cached, but it has to be validated on each request - headers: - cache-control: max-age=0, no-cache diff --git a/examples/cache/docker-compose.yaml b/examples/cache/docker-compose.yaml deleted file mode 100644 index 674c73d193b3..000000000000 --- a/examples/cache/docker-compose.yaml +++ /dev/null @@ -1,33 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - service1: - condition: service_healthy - service2: - condition: service_healthy - ports: - - "${PORT_PROXY:-8000}:8000" - - service1: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - "${CACHE_RESPONSES_YAML:-./responses.yaml}:/etc/responses.yaml" - - ./service.py:/code/service.py - environment: - - SERVICE_NAME=1 - - service2: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - "${CACHE_RESPONSES_YAML:-./responses.yaml}:/etc/responses.yaml" - - ./service.py:/code/service.py - environment: - - SERVICE_NAME=2 diff --git a/examples/cache/envoy.yaml b/examples/cache/envoy.yaml deleted file mode 100644 index b854214b565f..000000000000 --- a/examples/cache/envoy.yaml +++ /dev/null @@ -1,63 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1 - - match: - prefix: "/service/2" - route: - cluster: service2 - http_filters: - - name: "envoy.filters.http.cache" - typed_config: - "@type": "type.googleapis.com/envoy.extensions.filters.http.cache.v3.CacheConfig" - typed_config: - "@type": "type.googleapis.com/envoy.extensions.http.cache.simple_http_cache.v3.SimpleHttpCacheConfig" - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8080 - - name: service2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2 - port_value: 8080 diff --git a/examples/cache/example.rst b/examples/cache/example.rst deleted file mode 100644 index 2fe26289dc5b..000000000000 --- a/examples/cache/example.rst +++ /dev/null @@ -1,245 +0,0 @@ -.. _install_sandboxes_cache_filter: - -Cache filter -============ -.. TODO(yosrym93): When a documentation is written for a production-ready Cache Filter, link to it through this doc. - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we demonstrate how HTTP caching can be utilized in Envoy by using the Cache Filter. -The setup of this sandbox is based on the setup of the :ref:`Front Proxy sandbox `. - -All incoming requests are routed via the front Envoy, which acts as a reverse proxy sitting on -the edge of the ``envoymesh`` network. - -Port ``8000`` is exposed by :download:`docker-compose.yaml <_include/cache/docker-compose.yaml>` to handle ``HTTP`` calls -to the services. Two backend services are deployed behind the front Envoy, each with a sidecar Envoy. - -The front Envoy is configured to run the Cache Filter, which stores cacheable responses in an in-memory cache, -and serves it to subsequent requests. - -In this demo, the responses that are served by the deployed services are stored in :download:`responses.yaml <_include/cache/responses.yaml>`. - -This file is mounted to both services' containers, so any changes made to the stored responses while the services are -running should be instantly effective (no need to rebuild or rerun). - -For the purposes of the demo, a response's date of creation is appended to its body before being served. -An Etag is computed for every response for validation purposes, which only depends on the response body in the yaml file (i.e. the appended date is not taken into account). -Cached responses can be identified by having an ``age`` header. Validated responses can be identified by having a generation date older than the ``date`` header; -as when a response is validated the ``date`` header is updated, while the body stays the same. Validated responses do not have an ``age`` header. -Responses served from the backend service have no ``age`` header, and their ``date`` header is the same as their generation date. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/cache`` directory. - -.. code-block:: console - - $ pwd - envoy/examples/cache - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------- - cache_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp - cache_service1_1 python3 /code/service.py Up (healthy) - cache_service2_1 python3 /code/service.py Up (healthy) - -Step 2: Test Envoy's HTTP caching capabilities -********************************************** - -You can now send a request to both services via the ``front-envoy``. Note that since the two services have different routes, -identical requests to different services have different cache entries (i.e. a request sent to service 2 will not be served by a cached -response produced by service 1). - -To send a request: - -``curl -i localhost:8000/service//`` - -``service_no``: The service to send the request to, 1 or 2. - -``response``: The response that is being requested. The responses are found in -:download:`responses.yaml <_include/cache/responses.yaml>`. - - -The provided example responses are: - -- ``valid-for-minute`` - This response remains fresh in the cache for a minute. After which, the response gets validated by the backend service before being served from the cache. - If found to be updated, the new response is served (and cached). Otherwise, the cached response is served and refreshed. - -- ``private`` - This response is private; it cannot be stored by shared caches (such as proxies). It will always be served from the backend service. - -- ``no-cache`` - This response has to be validated every time before being served. - -You can change the responses' headers and bodies (or add new ones) while the sandbox is running to experiment. - -Example responses ------------------ - -1. valid-for-minute -^^^^^^^^^^^^^^^^^^^ - -.. code-block:: console - - $ curl -i localhost:8000/service/1/valid-for-minute - HTTP/1.1 200 OK - content-type: text/html; charset=utf-8 - content-length: 103 - cache-control: max-age=60 - custom-header: any value - etag: "172ae25df822c3299cf2248694b4ce23" - date: Fri, 11 Sep 2020 03:20:40 GMT - server: envoy - x-envoy-upstream-service-time: 11 - - This response will stay fresh for one minute - Response body generated at: Fri, 11 Sep 2020 03:20:40 GMT - -Naturally, response ``date`` header is the same time as the generated time. -Sending the same request after 30 seconds gives the same exact response with the same generation date, -but with an ``age`` header as it was served from cache: - -.. code-block:: console - - $ curl -i localhost:8000/service/1/valid-for-minute - HTTP/1.1 200 OK - content-type: text/html; charset=utf-8 - content-length: 103 - cache-control: max-age=60 - custom-header: any value - etag: "172ae25df822c3299cf2248694b4ce23" - date: Fri, 11 Sep 2020 03:20:40 GMT - server: envoy - x-envoy-upstream-service-time: 11 - age: 30 - - This response will stay fresh for one minute - Response body generated at: Fri, 11 Sep 2020 03:20:40 GMT - -After 1 minute and 1 second: - -.. code-block:: console - - $ curl -i localhost:8000/service/1/valid-for-minute - HTTP/1.1 200 OK - cache-control: max-age=60 - custom-header: any value - etag: "172ae25df822c3299cf2248694b4ce23" - date: Fri, 11 Sep 2020 03:21:41 GMT - server: envoy - x-envoy-upstream-service-time: 8 - content-length: 103 - content-type: text/html; charset=utf-8 - - This response will stay fresh for one minute - Response body generated at: Fri, 11 Sep 2020 03:20:40 GMT - -The same response was served after being validated with the backend service. -You can verify this as the response generation time is the same, -but the response ``date`` header was updated with the validation response date. -Also, no ``age`` header. - -Every time the response is validated, it stays fresh for another minute. -If the response body changes while the cached response is still fresh, -the cached response will still be served. The cached response will only be updated when it is no longer fresh. - -2. private -^^^^^^^^^^ - -.. code-block:: console - - $ curl -i localhost:8000/service/1/private - HTTP/1.1 200 OK - content-type: text/html; charset=utf-8 - content-length: 117 - cache-control: private - etag: "6bd80b59b2722606abf2b8d83ed2126d" - date: Fri, 11 Sep 2020 03:22:28 GMT - server: envoy - x-envoy-upstream-service-time: 7 - - This is a private response, it will not be cached by Envoy - Response body generated at: Fri, 11 Sep 2020 03:22:28 GMT - -No matter how many times you make this request, you will always receive a new response; -new date of generation, new ``date`` header, and no ``age`` header. - -3. no-cache -^^^^^^^^^^^ - -.. code-block:: console - - $ curl -i localhost:8000/service/1/no-cache - HTTP/1.1 200 OK - content-type: text/html; charset=utf-8 - content-length: 130 - cache-control: max-age=0, no-cache - etag: "ce39a53bd6bb8abdb2488a5a375397e4" - date: Fri, 11 Sep 2020 03:23:07 GMT - server: envoy - x-envoy-upstream-service-time: 7 - - This response can be cached, but it has to be validated on each request - Response body generated at: Fri, 11 Sep 2020 03:23:07 GMT - -After a few seconds: - -.. code-block:: console - - $ curl -i localhost:8000/service/1/no-cache - HTTP/1.1 200 OK - cache-control: max-age=0, no-cache - etag: "ce39a53bd6bb8abdb2488a5a375397e4" - date: Fri, 11 Sep 2020 03:23:12 GMT - server: envoy - x-envoy-upstream-service-time: 7 - content-length: 130 - content-type: text/html; charset=utf-8 - - This response can be cached, but it has to be validated on each request - Response body generated at: Fri, 11 Sep 2020 03:23:07 GMT - -You will receive a cached response that has the same generation time. -However, the ``date`` header will always be updated as this response will always be validated first. -Also, no ``age`` header. - -If you change the response body in the yaml file: - -.. code-block:: console - - $ curl -i localhost:8000/service/1/no-cache - HTTP/1.1 200 OK - content-type: text/html; charset=utf-8 - content-length: 133 - cache-control: max-age=0, no-cache - etag: "f4768af0ac9f6f54f88169a1f3ecc9f3" - date: Fri, 11 Sep 2020 03:24:10 GMT - server: envoy - x-envoy-upstream-service-time: 7 - - This response can be cached, but it has to be validated on each request!!! - Response body generated at: Fri, 11 Sep 2020 03:24:10 GMT - -You will receive a new response that's served from the backend service. -The new response will be cached for subsequent requests. - -You can also add new responses to the yaml file with different ``cache-control`` headers and start experimenting! - -.. seealso:: - - :ref:`Envoy Cache filter configuration ` - Learn more about configuring the Envoy Cache filter. - - `MDN Web Docs `_. - Learn more about caching and ``cache-control`` on the web. diff --git a/examples/cache/requirements.in b/examples/cache/requirements.in deleted file mode 100644 index c3726e8bfeee..000000000000 --- a/examples/cache/requirements.in +++ /dev/null @@ -1 +0,0 @@ -pyyaml diff --git a/examples/cache/requirements.txt b/examples/cache/requirements.txt deleted file mode 100644 index c160459ca0cf..000000000000 --- a/examples/cache/requirements.txt +++ /dev/null @@ -1,58 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -pyyaml==6.0.1 \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ - --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ - --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ - --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ - --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ - --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ - --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ - --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ - --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ - --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ - --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ - --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ - --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ - --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ - --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ - --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ - --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ - --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ - --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ - --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ - --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ - --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ - --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ - --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ - --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ - --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ - --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ - --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ - --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ - --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ - --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ - --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ - --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ - --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ - --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ - --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ - --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ - --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ - --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ - --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f - # via -r requirements.in diff --git a/examples/cache/responses.yaml b/examples/cache/responses.yaml deleted file mode 100644 index 1b20ac58f6a1..000000000000 --- a/examples/cache/responses.yaml +++ /dev/null @@ -1,13 +0,0 @@ -valid-for-minute: - body: This response will stay fresh for one minute - headers: - cache-control: max-age=60 - custom-header: any value -private: - body: This is a private response, it will not be cached by Envoy - headers: - cache-control: private -no-cache: - body: This response can be cached, but it has to be validated on each request - headers: - cache-control: max-age=0, no-cache diff --git a/examples/cache/service.py b/examples/cache/service.py deleted file mode 100644 index 4e85ec595261..000000000000 --- a/examples/cache/service.py +++ /dev/null @@ -1,84 +0,0 @@ -import hashlib -import os -import re -import datetime -from typing import Optional - -import yaml - -from aiohttp import web - -routes = web.RouteTableDef() - -# TOOD(phlax): move this to pytooling - -# Etag fun lifted from https://github.com/zhangkaizhao/aiohttp-etag - - -def _check_etag_header(request, computed_etag) -> bool: - # Find all weak and strong etag values from If-None-Match header - # because RFC 7232 allows multiple etag values in a single header. - etags = re.findall(r'\*|(?:W/)?"[^"]*"', request.headers.get("If-None-Match", "")) - if not etags: - return False - - match = False - if etags[0] == "*": - match = True - else: - # Use a weak comparison when comparing entity-tags. - def val(x: str) -> str: - return x[2:] if x.startswith("W/") else x - - for etag in etags: - if val(etag) == val(computed_etag): - match = True - break - return match - - -def _compute_etag(body) -> str: - hasher = hashlib.sha1() - hasher.update(body.encode()) - return f'"{hasher.hexdigest()}"' - - -def _set_etag_header(response, computed_etag) -> None: - response.headers["Etag"] = computed_etag - - -@routes.get("/service/{service_number}/{response_id}") -async def get(request): - service_number = request.match_info["service_number"] - response_id = request.match_info["response_id"] - stored_response = yaml.safe_load(open('/etc/responses.yaml', 'r')).get(response_id) - - if stored_response is None: - raise web.HTTPNotFound(reason="No response found with the given id") - - # Etag is computed for every response, which only depends on the response body in - # the yaml file (i.e. the appended date is not taken into account). - body = stored_response.get('body') - computed_etag = _compute_etag(body) - - if _check_etag_header(request, computed_etag): - return web.HTTPNotModified(headers={'ETag': computed_etag}) - - request_date = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") - response = web.Response(text=f"{body}\nResponse generated at: {request_date}\n") - - if stored_response.get('headers'): - response.headers.update(stored_response.get('headers')) - - _set_etag_header(response, computed_etag) - - return response - - -if __name__ == "__main__": - if not os.path.isfile('/etc/responses.yaml'): - print('Responses file not found at /etc/responses.yaml') - exit(1) - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/cache/verify.sh b/examples/cache/verify.sh deleted file mode 100755 index b8993be6bb24..000000000000 --- a/examples/cache/verify.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -e - -export NAME=cache - -export PORT_PROXY="${CACHE_PORT_PROXY:-10300}" -export CACHE_RESPONSES_YAML=./ci-responses.yaml - - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -check_validated() { - # Get the date header and the response generation timestamp - local _dates dates httpCode - _dates=$(grep -oP '\d\d:\d\d:\d\d' <<< "$1") - httpCode=$(echo "$response" | head -n 1 | cut -d ' ' -f 2) - while read -r line; do dates+=("$line"); done \ - <<< "$_dates" - - # Make sure it succeeds - if [[ $httpCode != "200" ]]; then - echo "ERROR: HTTP response code should be 200, but it was $httpCode" >&2 - return 1 - fi - - # Make sure they are different - if [[ ${dates[0]} == "${dates[1]}" ]]; then - echo "ERROR: validated responses should have a date AFTER the generation timestamp" >&2 - return 1 - fi - # Make sure there is no age header - if grep -q "age:" <<< "$1"; then - echo "ERROR: validated responses should not have an age header" >&2 - return 1 - fi -} - -check_cached() { - # Make sure there is an age header - if ! grep -q "age:" <<< "$1"; then - echo "ERROR: cached responses should have an age header" >&2 - return 1 - fi -} - -check_from_origin() { - # Get the date header and the response generation timestamp - local _dates dates - _dates=$(grep -oP '\d\d:\d\d:\d\d' <<< "$1") - while read -r line; do dates+=("$line"); done \ - <<< "$_dates" - # Make sure they are equal - if [[ ${dates[0]} != "${dates[1]}" ]]; then - echo "ERROR: responses from origin should have a date equal to the generation timestamp" >&2 - return 1 - fi - # Make sure there is no age header - if grep -q "age:" <<< "$1" ; then - echo "ERROR: responses from origin should not have an age header" >&2 - return 1 - fi -} - - -run_log "Valid-for-minute: First request should be served by the origin" -response=$(curl -si "localhost:${PORT_PROXY}/service/1/valid-for-minute") -check_from_origin "$response" - -run_log "Snooze for 2 seconds" -sleep 2 - -run_log "Valid-for-minute: Second request should be served from cache" -response=$(curl -si "localhost:${PORT_PROXY}/service/1/valid-for-minute") -check_cached "$response" - -run_log "Snooze for 3 more seconds" -sleep 3 - -run_log "Valid-for-minute: More than a minute has passed, this request should get a validated response" -response=$(curl -si "localhost:${PORT_PROXY}/service/1/valid-for-minute") -check_validated "$response" - -run_log "Private: Make 4 requests make sure they are all served by the origin" -for _ in {0..3}; do - response=$(curl -si "localhost:${PORT_PROXY}/service/1/private") - check_from_origin "$response" -done - -run_log "No-cache: First request should be served by the origin" -response=$(curl -si "localhost:${PORT_PROXY}/service/1/no-cache") -check_from_origin "$response" - -run_log "No-cache: Make 4 more requests and make sure they are all validated before being served from cache" -for _ in {0..3}; do - sleep 1 - response=$(curl -si "localhost:${PORT_PROXY}/service/1/no-cache") - check_validated "$response" -done diff --git a/examples/cors/README.md b/examples/cors/README.md deleted file mode 100644 index 1908b6455bf1..000000000000 --- a/examples/cors/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/cors.html). diff --git a/examples/cors/backend/docker-compose.yaml b/examples/cors/backend/docker-compose.yaml deleted file mode 100644 index 262f09fa74d0..000000000000 --- a/examples/cors/backend/docker-compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../../shared/envoy/Dockerfile - depends_on: - backend-service: - condition: service_healthy - ports: - - "${PORT_BACKEND:-8002}:10000" - - "${PORT_STATS:-8003}:8001" - - backend-service: - build: - context: ../../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py diff --git a/examples/cors/backend/envoy.yaml b/examples/cors/backend/envoy.yaml deleted file mode 100644 index 5feebc5e903c..000000000000 --- a/examples/cors/backend/envoy.yaml +++ /dev/null @@ -1,97 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: www - domains: - - "*" - typed_per_filter_config: - envoy.filters.http.cors: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy - allow_origin_string_match: - - safe_regex: - regex: \* - allow_methods: "GET" - filter_enabled: - default_value: - numerator: 100 - denominator: HUNDRED - runtime_key: cors.www.enabled - shadow_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - runtime_key: cors.www.shadow_enabled - routes: - - match: - prefix: "/cors/open" - route: - cluster: backend_service - - match: - prefix: "/cors/disabled" - route: - cluster: backend_service - typed_per_filter_config: - envoy.filters.http.cors: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy - filter_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - - match: - prefix: "/cors/restricted" - route: - cluster: backend_service - typed_per_filter_config: - envoy.filters.http.cors: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy - allow_origin_string_match: - - safe_regex: - regex: .*\.envoyproxy\.io - allow_methods: "GET" - - match: - prefix: "/" - route: - cluster: backend_service - http_filters: - - name: envoy.filters.http.cors - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: backend_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: backend_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend-service - port_value: 8080 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/cors/backend/service.py b/examples/cors/backend/service.py deleted file mode 100644 index 29ec77ade4a8..000000000000 --- a/examples/cors/backend/service.py +++ /dev/null @@ -1,14 +0,0 @@ -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/cors/{status}") -async def get(request): - return web.Response(text="Success!") - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/cors/example.rst b/examples/cors/example.rst deleted file mode 100644 index 616401b1a3e4..000000000000 --- a/examples/cors/example.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. _install_sandboxes_cors: - -CORS filter -=========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -Cross-Origin Resource Sharing (CORS) is a method of enforcing client-side -access controls on resources by specifying external domains that are able to -access certain or all routes of your domain. Browsers use the presence of HTTP -headers to determine if a response from a different origin is allowed. - -To help demonstrate how front-envoy can enforce CORS policies, we are -releasing a set of `docker compose `_ sandboxes -that deploy a frontend and backend service on different origins, both behind -front-envoy. - -The frontend service has a field to input the remote domain of your backend -service along with radio buttons to select the remote domain's CORS enforcement. -The CORS enforcement choices are: - - * Disabled: CORS is disabled on the route requested. This will result in a - client-side CORS error since the required headers to be considered a - valid CORS request are not present. - * Open: CORS is enabled on the route requested but the allowed origin is set - to ``*``. This is a very permissive policy and means that origin can request - data from this endpoint. - * Restricted: CORS is enabled on the route requested and the only allowed - origin is ``envoyproxy.io``. This will result in a client-side CORS error. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/cors/frontend`` directory, and start the containers: - -.. code-block:: console - - $ pwd - envoy/examples/cors/frontend - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------- - frontend_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp - frontend_frontend-service_1 python3 /code/service.py ... Up (healthy) - -Now, switch to the ``backend`` directory in the ``cors`` example, and start the containers: - -.. code-block:: console - - $ pwd - envoy/examples/cors/backend - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------------------- - backend_backend-service_1 python3 /code/service.py ... Up (healthy) - backend_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8002->8000/tcp, 0.0.0.0:8003->8001/tcp - -Step 2: Test Envoy's CORS capabilities -************************************** - -You can now open a browser to view your frontend service at http://localhost:8000. - -Results of the cross-origin request will be shown on the page under *Request Results*. - -Your browser's ``CORS`` enforcement logs can be found in the browser console. - -For example: - -.. code-block:: console - - Access to XMLHttpRequest at 'http://192.168.99.100:8002/cors/disabled' from origin 'http://192.168.99.101:8000' - has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. - -Step 3: Check stats of backend via admin -**************************************** - -When Envoy runs, it can listen to ``admin`` requests if a port is configured. - -In the example configs, the backend admin is bound to port ``8003``. - -If you browse to http://localhost:8003/stats you will be able to view -all of the Envoy stats for the backend. You should see the ``CORS`` stats for -invalid and valid origins increment as you make requests from the frontend cluster. - -.. code-block:: none - - http.ingress_http.cors.origin_invalid: 2 - http.ingress_http.cors.origin_valid: 7 - -.. seealso:: - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/cors/frontend/docker-compose.yaml b/examples/cors/frontend/docker-compose.yaml deleted file mode 100644 index 6546e87369ee..000000000000 --- a/examples/cors/frontend/docker-compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../../shared/envoy/Dockerfile - depends_on: - frontend-service: - condition: service_healthy - ports: - - "${PORT_PROXY:-8000}:10000" - - frontend-service: - build: - context: ../../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - - ./index.html:/code/index.html diff --git a/examples/cors/frontend/envoy.yaml b/examples/cors/frontend/envoy.yaml deleted file mode 100644 index e42bd5813c0f..000000000000 --- a/examples/cors/frontend/envoy.yaml +++ /dev/null @@ -1,48 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: services - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: frontend_service - http_filters: - - name: envoy.filters.http.cors - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: frontend_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: frontend_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: frontend-service - port_value: 8080 diff --git a/examples/cors/frontend/index.html b/examples/cors/frontend/index.html deleted file mode 100644 index 30e31d51c51b..000000000000 --- a/examples/cors/frontend/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - Envoy CORS Webpage - - - - -

- Envoy CORS Demo -

-

- This page requests an asset from another domain via cross-site XMLHttpRequest mitigated by Access Control.
- This scenario demonstrates a simple method.
- It does NOT dispatch a preflight request. -

-

- Enter the IP address of backend Docker container. As we are running Docker Compose this should just be localhost.
-

-
- -
-
-
CORS Enforcement
- Disabled
- Open
- Restricted
-
-
-
-

Request Results

-

-
-
- - - diff --git a/examples/cors/frontend/service.py b/examples/cors/frontend/service.py deleted file mode 100644 index 623b46dda882..000000000000 --- a/examples/cors/frontend/service.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/") -async def get(request): - file_dir = os.path.dirname(os.path.realpath(__file__)) - with open(f"{file_dir}/index.html") as f: - return web.Response(text=f.read(), content_type='text/html') - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/cors/verify.sh b/examples/cors/verify.sh deleted file mode 100755 index fc37386f265f..000000000000 --- a/examples/cors/verify.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e - -export NAME=cors -export PATHS=frontend,backend - -export PORT_PROXY="${CORS_PORT_PROXY:-10310}" -export PORT_BACKEND="${CORS_PORT_BACKEND:-10311}" -export PORT_STATS="${CORS_PORT_STATS:-10312}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test service" -responds_with \ - "Envoy CORS Webpage" \ - "http://localhost:${PORT_PROXY}" - -run_log "Test cors server: disabled" -responds_with \ - Success \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_BACKEND}/cors/disabled" -responds_without_header \ - access-control-allow-origin \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_BACKEND}/cors/disabled" - -run_log "Test cors server: open" -responds_with \ - Success \ - -H 'Origin: http://example.com' \ - "http://localhost:${PORT_BACKEND}/cors/open" -responds_with_header \ - "access-control-allow-origin: http://example.com" \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_BACKEND}/cors/open" - -run_log "Test cors server: restricted" -responds_with \ - Success \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_BACKEND}/cors/restricted" -responds_without_header \ - access-control-allow-origin \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_BACKEND}/cors/restricted" -responds_with_header \ - "access-control-allow-origin: http://foo.envoyproxy.io" \ - -H "Origin: http://foo.envoyproxy.io" \ - "http://localhost:${PORT_BACKEND}/cors/restricted" - -run_log "Check admin ingress stats" -responds_with \ - ingress_http.cors \ - "http://localhost:${PORT_STATS}/stats?filter=ingress_http" diff --git a/examples/csrf/README.md b/examples/csrf/README.md deleted file mode 100644 index fe8d62602b6b..000000000000 --- a/examples/csrf/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/csrf.html). diff --git a/examples/csrf/crosssite/docker-compose.yml b/examples/csrf/crosssite/docker-compose.yml deleted file mode 100644 index 96a5586e76a8..000000000000 --- a/examples/csrf/crosssite/docker-compose.yml +++ /dev/null @@ -1,19 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../../shared/envoy/Dockerfile - depends_on: - service: - condition: service_healthy - ports: - - "${PORT_CROSS:-8002}:10000" - - service: - build: - context: ../../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - - ../index.html:/code/index.html diff --git a/examples/csrf/crosssite/envoy.yaml b/examples/csrf/crosssite/envoy.yaml deleted file mode 100644 index 47cb74b3acb3..000000000000 --- a/examples/csrf/crosssite/envoy.yaml +++ /dev/null @@ -1,45 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: www - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: generic_service - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: generic_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: generic_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 8080 diff --git a/examples/csrf/crosssite/service.py b/examples/csrf/crosssite/service.py deleted file mode 100644 index 13220f175371..000000000000 --- a/examples/csrf/crosssite/service.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/") -async def get(request): - file_dir = os.path.dirname(os.path.realpath(__file__)) - with open(f"{file_dir}/index.html") as f: - return web.Response(text=f.read()) - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/csrf/example.rst b/examples/csrf/example.rst deleted file mode 100644 index 12223e76a06c..000000000000 --- a/examples/csrf/example.rst +++ /dev/null @@ -1,110 +0,0 @@ -.. _install_sandboxes_csrf: - -CSRF filter -=========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -Cross-Site Request Forgery (CSRF) is an attack that occurs when a malicious -third-party website exploits a vulnerability that allows them to submit an -undesired request on a user's behalf. To mitigate this attack this filter -checks where a request is coming from to determine if the request's origin -is the same as it's destination. - -To help demonstrate how front-envoy can enforce CSRF policies, we are releasing -a `docker compose `_ sandbox that -deploys a service with both a frontend and backed. This service will be started -on two different virtual machines with different origins. - -The frontend has a field to input the remote domain of where you would like to -send POST requests along with radio buttons to select the remote domain's CSRF -enforcement. The CSRF enforcement choices are: - - * Disabled: CSRF is disabled on the requested route. This will result in a - successful request since there is no CSRF enforcement. - * Shadow Mode: CSRF is not enforced on the requested route but will record - if the request contains a valid source origin. - * Enabled: CSRF is enabled and will return a 403 (Forbidden) status code when - a request is made from a different origin. - * Ignored: CSRF is enabled but the request type is a GET. This should bypass - the CSRF filter and return successfully. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/csrf/samesite`` directory, and start the containers: - -.. code-block:: console - - $ pwd - envoy/examples/csrf/samesite - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------------- - samesite_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp - samesite_service_1 python3 /code/service.py ... Up (healthy) - -Now, switch to the ``crosssite`` directory in the ``csrf`` example, and start the containers: - -.. code-block:: console - - $ pwd - envoy/examples/csrf/crosssite - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ---------------------------------------------------------------------------------------------------------- - crosssite_front-envoy_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 0.0.0.0:8002->8000/tcp - crosssite_service_1 python3 /code/service.py ... Up (healthy) - -Step 2: Test Envoy's CSRF capabilities -************************************** - -You can now open a browser at http://localhost:8002 to view your ``crosssite`` frontend service. - -Enter the IP of the ``samesite`` machine to demonstrate cross-site requests. Requests -with the enabled enforcement will fail. By default this field will be populated -with ``localhost``. - -To demonstrate same-site requests open the frontend service for ``samesite`` at http://localhost:8000 -and enter the IP address of the ``samesite`` machine as the destination. - -Results of the cross-site request will be shown on the page under *Request Results*. -Your browser's ``CSRF`` enforcement logs can be found in the browser console and in the -network tab. - -For example: - -.. code-block:: console - - Failed to load resource: the server responded with a status of 403 (Forbidden) - -If you change the destination to be the same as one displaying the website and -set the ``CSRF`` enforcement to enabled the request will go through successfully. - -Step 3: Check stats of backend via admin -**************************************** - -When Envoy runs, it can listen to ``admin`` requests if a port is configured. In -the example configs, the backend admin is bound to port ``8001``. - -If you browse to http://localhost:8001/stats you will be able to view -all of the Envoy stats for the backend. You should see the CORS stats for -invalid and valid origins increment as you make requests from the frontend cluster. - -.. code-block:: none - - http.ingress_http.csrf.missing_source_origin: 0 - http.ingress_http.csrf.request_invalid: 1 - http.ingress_http.csrf.request_valid: 0 - -.. seealso:: - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/csrf/index.html b/examples/csrf/index.html deleted file mode 100644 index e39a5cb61659..000000000000 --- a/examples/csrf/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Envoy CSRF Wepage - - - - -

- Envoy CSRF Demo -

-

- This page demonstrates a few scenarios for CSRF. -

-

- Enter the IP address of the destination Docker container.
-

-
- -
-
-
CSRF Enforcement
- Disabled
- Shadow Mode
- Enabled
- Ignored
- Additional Origin
-
-
-
-

Request Results

-

-
-
- - - diff --git a/examples/csrf/samesite/docker-compose.yml b/examples/csrf/samesite/docker-compose.yml deleted file mode 100644 index feabf37afc92..000000000000 --- a/examples/csrf/samesite/docker-compose.yml +++ /dev/null @@ -1,20 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../../shared/envoy/Dockerfile - depends_on: - service: - condition: service_healthy - ports: - - "${PORT_SAME:-8000}:10000" - - "${PORT_STATS:-8001}:8001" - - service: - build: - context: ../../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - - ../index.html:/code/index.html diff --git a/examples/csrf/samesite/envoy.yaml b/examples/csrf/samesite/envoy.yaml deleted file mode 100644 index cffeea09c790..000000000000 --- a/examples/csrf/samesite/envoy.yaml +++ /dev/null @@ -1,123 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: www - domains: - - "*" - typed_per_filter_config: - envoy.filters.http.cors: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy - allow_origin_string_match: - - safe_regex: - regex: \* - filter_enabled: - default_value: - numerator: 100 - denominator: HUNDRED - envoy.filters.http.csrf: - "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy - filter_enabled: - default_value: - numerator: 100 - denominator: HUNDRED - runtime_key: csrf.www.enabled - shadow_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - runtime_key: csrf.www.shadow_enabled - routes: - - match: - prefix: "/csrf/disabled" - route: - cluster: generic_service - typed_per_filter_config: - envoy.filters.http.csrf: - "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy - filter_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - - match: - prefix: "/csrf/shadow" - route: - cluster: generic_service - typed_per_filter_config: - envoy.filters.http.csrf: - "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy - filter_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - shadow_enabled: - default_value: - numerator: 100 - denominator: HUNDRED - - match: - prefix: "/csrf/additional_origin" - route: - cluster: generic_service - typed_per_filter_config: - envoy.filters.http.csrf: - "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy - filter_enabled: - default_value: - numerator: 100 - denominator: HUNDRED - additional_origins: - - safe_regex: - regex: .* - - match: - prefix: "/" - route: - cluster: generic_service - http_filters: - - name: envoy.filters.http.cors - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors - - name: envoy.filters.http.csrf - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy - filter_enabled: - default_value: - numerator: 0 - denominator: HUNDRED - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: generic_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: generic_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 8080 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/csrf/samesite/service.py b/examples/csrf/samesite/service.py deleted file mode 100644 index 1f9dde7b1a20..000000000000 --- a/examples/csrf/samesite/service.py +++ /dev/null @@ -1,23 +0,0 @@ -import os - -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.post("/csrf/{status}") -async def csrf_with_status(request): - return web.Response(text="Success!") - - -@routes.get("/") -async def get(request): - file_dir = os.path.dirname(os.path.realpath(__file__)) - with open(f"{file_dir}/index.html") as f: - return web.Response(text=f.read()) - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/csrf/start_service.sh b/examples/csrf/start_service.sh deleted file mode 100644 index 856194b13590..000000000000 --- a/examples/csrf/start_service.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -python3 /code/service.py & -envoy -c /etc/service-envoy.yaml --service-cluster service diff --git a/examples/csrf/verify.sh b/examples/csrf/verify.sh deleted file mode 100755 index f2188a5e7815..000000000000 --- a/examples/csrf/verify.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash -e - -export NAME=csrf -export PATHS=samesite,crosssite - -export PORT_SAME="${CSRF_PORT_SAME:-10320}" -export PORT_STATS="${CSRF_PORT_STATS:-10321}" -export PORT_CROSS="${CSRF_PORT_CROSS:-10322}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test services" -responds_with \ - "Envoy CSRF Demo" \ - "http://localhost:${PORT_CROSS}" -responds_with \ - "Envoy CSRF Demo" \ - "http://localhost:${PORT_SAME}" - -run_log "Test stats server" -responds_with \ - ":" \ - "http://localhost:${PORT_STATS}/stats" - -run_log "Test csrf server: disabled" -responds_with \ - Success \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/disabled" -responds_with_header \ - "access-control-allow-origin: http://example.com" \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/disabled" - -run_log "Test csrf server: shadow" -responds_with \ - Success \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/shadow" -responds_with_header \ - "access-control-allow-origin: http://example.com" \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/shadow" - -run_log "Test csrf server: enabled" -responds_with \ - "Invalid origin" \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/enabled" -responds_with_header \ - "HTTP/1.1 403 Forbidden" \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/enabled" - -run_log "Test csrf server: additional_origin" -responds_with \ - Success \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/additional_origin" -responds_with_header \ - "access-control-allow-origin: http://example.com" \ - -X POST \ - -H "Origin: http://example.com" \ - "http://localhost:${PORT_SAME}/csrf/additional_origin" - -run_log "Check admin ingress stats" -responds_with \ - ingress_http.csrf \ - "http://localhost:${PORT_STATS}/stats?filter=ingress_http" diff --git a/examples/double-proxy/README.md b/examples/double-proxy/README.md deleted file mode 100644 index 42ac1ea14aab..000000000000 --- a/examples/double-proxy/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/double-proxy.html). diff --git a/examples/double-proxy/docker-compose.yaml b/examples/double-proxy/docker-compose.yaml deleted file mode 100644 index 23e3a7c0a482..000000000000 --- a/examples/double-proxy/docker-compose.yaml +++ /dev/null @@ -1,84 +0,0 @@ -services: - - proxy-frontend: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - networks: - edge: - depends_on: - app: - condition: service_healthy - ports: - - "10000:10000" - - app: - build: - context: ../shared/python - target: aiohttp-postgres-service - depends_on: - proxy-postgres-frontend: - condition: service_started - networks: - edge: - postgres-frontend: - volumes: - - ./service.py:/code/service.py - - proxy-postgres-frontend: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-double-proxy-frontend - args: - ENVOY_CONFIG: envoy-frontend.yaml - depends_on: - proxy-postgres-backend: - condition: service_started - networks: - postgres-frontend: - aliases: - - postgres - postgres-in-between: - - proxy-postgres-backend: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-double-proxy-backend - args: - ENVOY_CONFIG: envoy-backend.yaml - depends_on: - postgres: - condition: service_healthy - networks: - postgres-backend: - postgres-in-between: - aliases: - - proxy-postgres-backend.example.com - - postgres: - build: - context: ../shared/postgres - networks: - postgres-backend: - environment: - # WARNING! Do not use it on production environments because this will - # allow anyone with access to the Postgres port to access your - # database without a password, even if POSTGRES_PASSWORD is set. - # See PostgreSQL documentation about "trust": - # https://www.postgresql.org/docs/current/auth-trust.html - POSTGRES_HOST_AUTH_METHOD: trust - -networks: - edge: - name: edge - - postgres-backend: - name: postgres-backend - - postgres-frontend: - name: postgres-frontend - - postgres-in-between: - name: postgres-in-between diff --git a/examples/double-proxy/envoy-backend.yaml b/examples/double-proxy/envoy-backend.yaml deleted file mode 100644 index 49c8306f35d0..000000000000 --- a/examples/double-proxy/envoy-backend.yaml +++ /dev/null @@ -1,49 +0,0 @@ -static_resources: - listeners: - - name: postgres_listener - address: - socket_address: - address: 0.0.0.0 - port_value: 5432 - listener_filters: - - name: "envoy.filters.listener.tls_inspector" - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector - filter_chains: - - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - stat_prefix: postgres_tcp - cluster: postgres_cluster - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - require_client_certificate: true - common_tls_context: - tls_certificates: - - certificate_chain: - filename: certs/servercert.pem - private_key: - filename: certs/serverkey.pem - validation_context: - match_typed_subject_alt_names: - - san_type: DNS - matcher: - exact: proxy-postgres-frontend.example.com - trusted_ca: - filename: certs/cacert.pem - - clusters: - - name: postgres_cluster - type: STRICT_DNS - load_assignment: - cluster_name: postgres_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: postgres - port_value: 5432 diff --git a/examples/double-proxy/envoy-frontend.yaml b/examples/double-proxy/envoy-frontend.yaml deleted file mode 100644 index 21fa643e62ed..000000000000 --- a/examples/double-proxy/envoy-frontend.yaml +++ /dev/null @@ -1,44 +0,0 @@ -static_resources: - listeners: - - name: postgres_listener - address: - socket_address: - address: 0.0.0.0 - port_value: 5432 - filter_chains: - - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - stat_prefix: postgres_tcp - cluster: postgres_cluster - - clusters: - - name: postgres_cluster - type: STRICT_DNS - load_assignment: - cluster_name: postgres_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: proxy-postgres-backend.example.com - port_value: 5432 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - common_tls_context: - tls_certificates: - - certificate_chain: - filename: certs/clientcert.pem - private_key: - filename: certs/clientkey.pem - validation_context: - match_typed_subject_alt_names: - - san_type: DNS - matcher: - exact: proxy-postgres-backend.example.com - trusted_ca: - filename: certs/cacert.pem diff --git a/examples/double-proxy/envoy.yaml b/examples/double-proxy/envoy.yaml deleted file mode 100644 index f3e77fc147cf..000000000000 --- a/examples/double-proxy/envoy.yaml +++ /dev/null @@ -1,42 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service1 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: app - port_value: 8080 diff --git a/examples/double-proxy/example.rst b/examples/double-proxy/example.rst deleted file mode 100644 index 3089089190e0..000000000000 --- a/examples/double-proxy/example.rst +++ /dev/null @@ -1,190 +0,0 @@ -.. _install_sandboxes_double_proxy: - -Double proxy (with ``mTLS`` encryption) -======================================= - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`openssl ` - Generate ``SSL`` keys and certificates. - -This sandbox demonstrates a basic "double proxy" configuration, in which a simple ``aiohttp`` app -connects to a PostgreSQL database, with two Envoy proxies in between. - -``Envoy (front)`` -> ``aiohttp`` -> ``Envoy (postgres-front)`` -> ``Envoy (postgres-back)`` -> ``PostgreSQL`` - -This type of setup is common in a service mesh where Envoy acts as a "sidecar" between individual services. - -It can also be useful as a way of providing access for application servers to upstream services or -databases that may be in a different location or subnet, outside of a service mesh or sidecar-based setup. - -Another common use case is with Envoy configured to provide "Points of presence" at the edges of the cloud, -and to relay requests to upstream servers and services. - -This example encrypts the transmission of data between the two middle proxies and provides mutual authentication -using ``mTLS``. - -This can be useful if the proxies are physically separated or transmit data over untrusted networks. - -In order to use the sandbox you will first need to generate the necessary ``SSL`` keys and certificates. - -This example walks through creating a certificate authority, and using it to create a domain key and sign -certificates for the proxies. - -Change to the ``examples/double-proxy`` directory. - -Step 1: Create a certificate authority -************************************** - -First create a key for the certificate authority: - -.. code-block:: console - - $ pwd - envoy/examples/double-proxy - $ mkdir -p certs - $ openssl genrsa -out certs/ca.key 4096 - Generating RSA private key, 4096 bit long modulus (2 primes) - ..........++++ - ..........................................................................................................++++ - e is 65537 (0x010001) - -Now use the key to generate a certificate authority certificate. - -If you wish, you can interactively alter the fields in the certificate. - -For the purpose of this example, the defaults should be sufficient. - -.. code-block:: console - - $ openssl req -x509 -new -nodes -key certs/ca.key -sha256 -days 1024 -out certs/ca.crt - - You are about to be asked to enter information that will be incorporated - into your certificate request. - What you are about to enter is what is called a Distinguished Name or a DN. - There are quite a few fields but you can leave some blank - For some fields there will be a default value, - If you enter '.', the field will be left blank. - ----- - Country Name (2 letter code) [AU]: - State or Province Name (full name) [Some-State]: - Locality Name (eg, city) []: - Organization Name (eg, company) [Internet Widgits Pty Ltd]: - Organizational Unit Name (eg, section) []: - Common Name (e.g. server FQDN or YOUR name) []: - Email Address []: - -Step 2: Create a domain key -*************************** - -Create a key for the example domain: - -.. code-block:: console - - $ openssl genrsa -out certs/example.com.key 2048 - Generating RSA private key, 2048 bit long modulus (2 primes) - ..+++++ - .................................................+++++ - e is 65537 (0x010001) - -Step 3: Generate certificate signing requests for the proxies -************************************************************* - -Use the domain key to generate certificate signing requests for each of the proxies: - -.. code-block:: console - - $ openssl req -new -sha256 \ - -key certs/example.com.key \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-frontend.example.com" \ - -out certs/proxy-postgres-frontend.example.com.csr - $ openssl req -new -sha256 \ - -key certs/example.com.key \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-backend.example.com" \ - -out certs/proxy-postgres-backend.example.com.csr - -Step 4: Sign the proxy certificates -*********************************** - -You can now use the certificate authority that you created to sign the certificate requests. - -Note the ``subjectAltName``. This is used for reciprocally matching and validating the certificates. - -.. code-block:: console - - $ openssl x509 -req \ - -in certs/proxy-postgres-frontend.example.com.csr \ - -CA certs/ca.crt \ - -CAkey certs/ca.key \ - -CAcreateserial \ - -extfile <(printf "subjectAltName=DNS:proxy-postgres-frontend.example.com") \ - -out certs/postgres-frontend.example.com.crt \ - -days 500 \ - -sha256 - Signature ok - subject=C = US, ST = CA, O = "MyExample, Inc.", CN = proxy-postgres-frontend.example.com - Getting CA Private Key - - $ openssl x509 -req \ - -in certs/proxy-postgres-backend.example.com.csr \ - -CA certs/ca.crt \ - -CAkey certs/ca.key \ - -CAcreateserial \ - -extfile <(printf "subjectAltName=DNS:proxy-postgres-backend.example.com") \ - -out certs/postgres-backend.example.com.crt \ - -days 500 \ - -sha256 - Signature ok - subject=C = US, ST = CA, O = "MyExample, Inc.", CN = proxy-postgres-backend.example.com - Getting CA Private Key - -At this point you should have the necessary keys and certificates to secure the connection between -the proxies. - -The keys and certificates are stored in the ``certs/`` directory. - -Step 5: Start all of our containers -*********************************** - -Build and start the containers. - -This will load the required keys and certificates into the frontend and backend proxies. - -.. code-block:: console - - $ pwd - envoy/examples/double-proxy - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------- - double-proxy_app_1 python3 /code/service.py Up (healthy) - double-proxy_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp - double-proxy_proxy-frontend_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - double-proxy_proxy-postgres-backend_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - double-proxy_proxy-postgres-frontend_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - -Step 6: Check the ``aiohttp`` app can connect to the database -************************************************************* - -Checking the response at http://localhost:10000, you should see the output from the ``aiohttp`` app: - -.. code-block:: console - - $ curl -s http://localhost:10000 - Connected to Postgres, version: PostgreSQL 13.0 (Debian 13.0-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit - -.. seealso:: - - :ref:`Securing Envoy quick start guide ` - Outline of key concepts for securing Envoy. - - :ref:`TLS sandbox ` - Examples of various ``TLS`` termination patterns with Envoy. diff --git a/examples/double-proxy/requirements.in b/examples/double-proxy/requirements.in deleted file mode 100644 index 37ec460f84e8..000000000000 --- a/examples/double-proxy/requirements.in +++ /dev/null @@ -1 +0,0 @@ -psycopg2-binary diff --git a/examples/double-proxy/service.py b/examples/double-proxy/service.py deleted file mode 100644 index 6e166755e7f2..000000000000 --- a/examples/double-proxy/service.py +++ /dev/null @@ -1,22 +0,0 @@ -from aiohttp import web - -# TODO(phlax): shift to aiopg -import psycopg2 - -routes = web.RouteTableDef() - - -@routes.get("/") -async def get(request): - conn = psycopg2.connect("host=postgres user=postgres") - cur = conn.cursor() - cur.execute('SELECT version()') - msg = 'Connected to Postgres, version: %s' % cur.fetchone() - cur.close() - return web.Response(text=msg) - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/double-proxy/verify.sh b/examples/double-proxy/verify.sh deleted file mode 100755 index 6dab851b9300..000000000000 --- a/examples/double-proxy/verify.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -e - -export NAME=double-proxy -export MANUAL=true - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -mkdir -p certs - -# TODO(phlax): remove openssl bug workaround when openssl/ubuntu are updated -# see #15555 for more info -touch ~/.rnd - -run_log "Create a cert authority" -openssl genrsa -out certs/ca.key 4096 -openssl req -batch -x509 -new -nodes -key certs/ca.key -sha256 -days 1024 -out certs/ca.crt - -run_log "Create a domain key" -openssl genrsa -out certs/example.com.key 2048 - -run_log "Generate signing requests for each proxy" -openssl req -new -sha256 \ - -key certs/example.com.key \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-frontend.example.com" \ - -out certs/proxy-postgres-frontend.example.com.csr -openssl req -new -sha256 \ - -key certs/example.com.key \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=proxy-postgres-backend.example.com" \ - -out certs/proxy-postgres-backend.example.com.csr - -run_log "Generate certificates for each proxy" -openssl x509 -req \ - -in certs/proxy-postgres-frontend.example.com.csr \ - -CA certs/ca.crt \ - -CAkey certs/ca.key \ - -CAcreateserial \ - -extfile <(printf "subjectAltName=DNS:proxy-postgres-frontend.example.com") \ - -out certs/postgres-frontend.example.com.crt \ - -days 500 \ - -sha256 -openssl x509 -req \ - -in certs/proxy-postgres-backend.example.com.csr \ - -CA certs/ca.crt \ - -CAkey certs/ca.key \ - -CAcreateserial \ - -extfile <(printf "subjectAltName=DNS:proxy-postgres-backend.example.com") \ - -out certs/postgres-backend.example.com.crt \ - -days 500 \ - -sha256 - -bring_up_example - -run_log "Test app/db connection" -responds_with \ - "Connected to Postgres, version: PostgreSQL" \ - http://localhost:10000 diff --git a/examples/dynamic-config-cp/README.md b/examples/dynamic-config-cp/README.md deleted file mode 100644 index 936e6dd00f7a..000000000000 --- a/examples/dynamic-config-cp/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/dynamic-configuration-control-plane.html). diff --git a/examples/dynamic-config-cp/_include/response-config-active-clusters-updated.json b/examples/dynamic-config-cp/_include/response-config-active-clusters-updated.json deleted file mode 100644 index 4ff0f03a2c1a..000000000000 --- a/examples/dynamic-config-cp/_include/response-config-active-clusters-updated.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "version_info": "2", - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "example_proxy_cluster", - "type": "LOGICAL_DNS", - "connect_timeout": "5s", - "dns_lookup_family": "V4_ONLY", - "load_assignment": { - "cluster_name": "example_proxy_cluster", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "service2", - "port_value": 8080 - } - } - } - } - ] - } - ] - } - }, - "last_updated": "2020-10-26T14:35:17.360Z" - } -] diff --git a/examples/dynamic-config-cp/_include/response-config-active-clusters.json b/examples/dynamic-config-cp/_include/response-config-active-clusters.json deleted file mode 100644 index f51d9df5e527..000000000000 --- a/examples/dynamic-config-cp/_include/response-config-active-clusters.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "version_info": "1", - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "example_proxy_cluster", - "type": "LOGICAL_DNS", - "connect_timeout": "5s", - "dns_lookup_family": "V4_ONLY", - "load_assignment": { - "cluster_name": "example_proxy_cluster", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "service1", - "port_value": 8080 - } - } - } - } - ] - } - ] - } - }, - "last_updated": "2020-10-25T20:37:05.838Z" - } -] diff --git a/examples/dynamic-config-cp/_include/response-config-cluster.json b/examples/dynamic-config-cp/_include/response-config-cluster.json deleted file mode 100644 index 9df9306e0f45..000000000000 --- a/examples/dynamic-config-cp/_include/response-config-cluster.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "cluster": { - "@type": "type.googleapis.com/envoy.api.v2.Cluster", - "name": "xds_cluster", - "type": "STRICT_DNS", - "connect_timeout": "1s", - "http2_protocol_options": {}, - "load_assignment": { - "cluster_name": "xds_cluster", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "go-control-plane", - "port_value": 18000 - } - } - } - } - ] - } - ] - } - }, - "last_updated": "2020-10-25T20:20:54.897Z" - } -] diff --git a/examples/dynamic-config-cp/docker-compose.yaml b/examples/dynamic-config-cp/docker-compose.yaml deleted file mode 100644 index b83883f42b21..000000000000 --- a/examples/dynamic-config-cp/docker-compose.yaml +++ /dev/null @@ -1,31 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - - service1 - - service2 - ports: - - 10000:10000 - - 19000:19000 - - service1: - build: - context: ../shared/echo - hostname: service1 - - service2: - build: - context: ../shared/echo - hostname: service2 - - go-control-plane: - build: - context: . - dockerfile: ../shared/golang/Dockerfile - target: golang-control-plane - command: /usr/local/bin/example - healthcheck: - test: nc -zv localhost 18000 diff --git a/examples/dynamic-config-cp/envoy.yaml b/examples/dynamic-config-cp/envoy.yaml deleted file mode 100644 index 4fa89ba5852b..000000000000 --- a/examples/dynamic-config-cp/envoy.yaml +++ /dev/null @@ -1,39 +0,0 @@ -node: - cluster: test-cluster - id: test-id - -dynamic_resources: - ads_config: - api_type: GRPC - grpc_services: - - envoy_grpc: - cluster_name: xds_cluster - cds_config: - ads: {} - lds_config: - ads: {} - -static_resources: - clusters: - - type: STRICT_DNS - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - name: xds_cluster - load_assignment: - cluster_name: xds_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: go-control-plane - port_value: 18000 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 19000 diff --git a/examples/dynamic-config-cp/example.rst b/examples/dynamic-config-cp/example.rst deleted file mode 100644 index 53968bee3c50..000000000000 --- a/examples/dynamic-config-cp/example.rst +++ /dev/null @@ -1,223 +0,0 @@ -.. _install_sandboxes_dynamic_config_cp: - -Dynamic configuration (control plane) -===================================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`jq ` - Parse ``json`` output from the upstream echo servers. - -This example walks through configuring Envoy using the `Go Control Plane `_ -reference implementation. - -It demonstrates how configuration provided to Envoy persists, even when the control plane is not available, -and provides a trivial example of how to update Envoy's configuration dynamically. - -Step 1: Start the proxy container -********************************* - -Change directory to ``examples/dynamic-config-cp`` in the Envoy repository. - -First build the containers and start the ``proxy`` container. - -This should also start two upstream ``HTTP`` echo servers, ``service1`` and ``service2``. - -The control plane has not yet been started. - -.. code-block:: console - - $ pwd - envoy/examples/dynamic-config-cp - $ docker compose pull - $ docker compose up --build -d proxy - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------ - dynamic-config-cp_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:19000->19000/tcp - dynamic-config-cp_service1_1 /bin/echo-server Up 8080/tcp - dynamic-config-cp_service2_1 /bin/echo-server Up 8080/tcp - -Step 2: Check initial config and web response -********************************************* - -As we have not yet started the control plane, nothing should be responding on port ``10000``. - -.. code-block:: console - - $ curl http://localhost:10000 - curl: (56) Recv failure: Connection reset by peer - -Dump the proxy's :ref:`static_clusters ` -configuration and you should see the cluster named ``xds_cluster`` configured for the control plane: - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq '.configs[1].static_clusters' - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-cp/_include/response-config-cluster.json - :language: json - :emphasize-lines: 10, 18-19 - -No :ref:`dynamic_active_clusters ` -have been configured yet: - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq '.configs[1].dynamic_active_clusters' - null - -Step 3: Start the control plane -******************************* - -Start up the ``go-control-plane`` service. - -You may need to wait a moment or two for it to become ``healthy``. - -.. code-block:: console - - $ docker compose up --build -d go-control-plane - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------------------- - dynamic-config-cp_go-control-plane_1 bin/example -debug Up (healthy) - dynamic-config-cp_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:19000->19000/tcp - dynamic-config-cp_service1_1 /bin/echo-server Up 8080/tcp - dynamic-config-cp_service2_1 /bin/echo-server Up 8080/tcp - -Step 4: Query the proxy -*********************** - -Once the control plane has started and is ``healthy``, you should be able to make a request to port ``10000``, -which will be served by ``service1``. - -.. code-block:: console - - $ curl http://localhost:10000 - Request served by service1 - - HTTP/1.1 GET / - - Host: localhost:10000 - Accept: */* - X-Forwarded-Proto: http - X-Request-Id: 1d93050e-f39c-4602-90f8-a124d6e78d26 - X-Envoy-Expected-Rq-Timeout-Ms: 15000 - Content-Length: 0 - User-Agent: curl/7.72.0 - -Step 5: Dump Envoy's ``dynamic_active_clusters`` config -******************************************************* - -If you now dump the proxy's :ref:`dynamic_active_clusters ` -configuration, you should see it is configured with the ``example_proxy_cluster`` pointing to ``service1``, and a version of ``1``. - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq '.configs[1].dynamic_active_clusters' - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-cp/_include/response-config-active-clusters.json - :language: json - :emphasize-lines: 3, 11, 19-20 - -Step 6: Stop the control plane -****************************** - -Stop the ``go-control-plane`` service: - -.. code-block:: console - - $ docker compose stop go-control-plane - -The Envoy proxy should continue proxying responses from ``service1``. - -.. code-block:: console - - $ curl http://localhost:10000 | grep "served by" - Request served by service1 - -Step 7: Edit ``go`` file and restart the control plane -****************************************************** - -The example setup starts the ``go-control-plane`` -service with a custom :download:`resource.go ` file which -specifies the configuration provided to Envoy. - -Update this to have Envoy proxy instead to ``service2``. - -Edit ``resource.go`` in the dynamic configuration example folder and change the ``UpstreamHost`` -from ``service1`` to ``service2``: - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-cp/resource.go - :language: go - :lines: 34-43 - :lineno-start: 35 - :emphasize-lines: 6 - :linenos: - -Further down in this file you must also change the configuration snapshot version number from -``"1"`` to ``"2"`` to ensure Envoy sees the configuration as newer: - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-cp/resource.go - :language: go - :lineno-start: 175 - :lines: 174-186 - :emphasize-lines: 3 - :linenos: - -Now rebuild and restart the control plane: - -.. code-block:: console - - $ docker compose up --build -d go-control-plane - -You may need to wait a moment or two for the ``go-control-plane`` service to become ``healthy`` again. - -Step 8: Check Envoy uses the updated configuration -************************************************** - -Now when you make a request to the proxy it should be served by the ``service2`` upstream service. - -.. code-block:: console - - $ curl http://localhost:10000 | grep "served by" - Request served by service2 - -Dumping the :ref:`dynamic_active_clusters ` -you should see the cluster configuration now has a version of ``2``, and ``example_proxy_cluster`` -is configured to proxy to ``service2``: - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq '.configs[1].dynamic_active_clusters' - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-cp/_include/response-config-active-clusters-updated.json - :language: json - :emphasize-lines: 3, 11, 19-20 - -.. note:: - In this example we increment the version for simplicity. - - Any change to the version will trigger an update in Envoy, and ordering is not significant - (see :ref:`xDS protocol docs for further information about updates `). - -.. seealso:: - - :ref:`Dynamic configuration (control plane) quick start guide ` - Quick start guide to dynamic configuration of Envoy with a control plane. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - :ref:`Dynamic configuration (filesystem) sandbox ` - Configure Envoy using filesystem-based dynamic configuration. - - `Go control plane `_ - Reference implementation of Envoy control plane written in ``go``. diff --git a/examples/dynamic-config-cp/resource.go b/examples/dynamic-config-cp/resource.go deleted file mode 100644 index d9c5aa6288f3..000000000000 --- a/examples/dynamic-config-cp/resource.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2020 Envoyproxy Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package example - -import ( - "time" - - "github.com/golang/protobuf/ptypes" - - cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" - core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" - endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" - listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" - route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" - router "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3" - hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" - - "github.com/envoyproxy/go-control-plane/pkg/cache/types" - cache "github.com/envoyproxy/go-control-plane/pkg/cache/v3" - resource "github.com/envoyproxy/go-control-plane/pkg/resource/v3" - "github.com/envoyproxy/go-control-plane/pkg/wellknown" -) - -const ( - ClusterName = "example_proxy_cluster" - RouteName = "local_route" - ListenerName = "listener_0" - ListenerPort = 10000 - UpstreamHost = "service1" - UpstreamPort = 8080 -) - -func makeCluster(clusterName string) *cluster.Cluster { - return &cluster.Cluster{ - Name: clusterName, - ConnectTimeout: ptypes.DurationProto(5 * time.Second), - ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_LOGICAL_DNS}, - LbPolicy: cluster.Cluster_ROUND_ROBIN, - LoadAssignment: makeEndpoint(clusterName), - DnsLookupFamily: cluster.Cluster_V4_ONLY, - } -} - -func makeEndpoint(clusterName string) *endpoint.ClusterLoadAssignment { - return &endpoint.ClusterLoadAssignment{ - ClusterName: clusterName, - Endpoints: []*endpoint.LocalityLbEndpoints{{ - LbEndpoints: []*endpoint.LbEndpoint{{ - HostIdentifier: &endpoint.LbEndpoint_Endpoint{ - Endpoint: &endpoint.Endpoint{ - Address: &core.Address{ - Address: &core.Address_SocketAddress{ - SocketAddress: &core.SocketAddress{ - Protocol: core.SocketAddress_TCP, - Address: UpstreamHost, - PortSpecifier: &core.SocketAddress_PortValue{ - PortValue: UpstreamPort, - }, - }, - }, - }, - }, - }, - }}, - }}, - } -} - -func makeRoute(routeName string, clusterName string) *route.RouteConfiguration { - return &route.RouteConfiguration{ - Name: routeName, - VirtualHosts: []*route.VirtualHost{{ - Name: "local_service", - Domains: []string{"*"}, - Routes: []*route.Route{{ - Match: &route.RouteMatch{ - PathSpecifier: &route.RouteMatch_Prefix{ - Prefix: "/", - }, - }, - Action: &route.Route_Route{ - Route: &route.RouteAction{ - ClusterSpecifier: &route.RouteAction_Cluster{ - Cluster: clusterName, - }, - }, - }, - }}, - }}, - } -} - -func makeHTTPListener(listenerName string, route string) *listener.Listener { - router := &router.Router{} - routerpb, err := ptypes.MarshalAny(router) - if err != nil { - panic(err) - } - - // HTTP filter configuration - manager := &hcm.HttpConnectionManager{ - CodecType: hcm.HttpConnectionManager_AUTO, - StatPrefix: "http", - RouteSpecifier: &hcm.HttpConnectionManager_Rds{ - Rds: &hcm.Rds{ - ConfigSource: makeConfigSource(), - RouteConfigName: route, - }, - }, - HttpFilters: []*hcm.HttpFilter{{ - Name: wellknown.Router, - ConfigType: &hcm.HttpFilter_TypedConfig{ - TypedConfig: routerpb, - }, - }}, - } - pbst, err := ptypes.MarshalAny(manager) - if err != nil { - panic(err) - } - - return &listener.Listener{ - Name: listenerName, - Address: &core.Address{ - Address: &core.Address_SocketAddress{ - SocketAddress: &core.SocketAddress{ - Protocol: core.SocketAddress_TCP, - Address: "0.0.0.0", - PortSpecifier: &core.SocketAddress_PortValue{ - PortValue: ListenerPort, - }, - }, - }, - }, - FilterChains: []*listener.FilterChain{{ - Filters: []*listener.Filter{{ - Name: wellknown.HTTPConnectionManager, - ConfigType: &listener.Filter_TypedConfig{ - TypedConfig: pbst, - }, - }}, - }}, - } -} - -func makeConfigSource() *core.ConfigSource { - source := &core.ConfigSource{} - source.ResourceApiVersion = resource.DefaultAPIVersion - source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{ - ApiConfigSource: &core.ApiConfigSource{ - TransportApiVersion: resource.DefaultAPIVersion, - ApiType: core.ApiConfigSource_GRPC, - SetNodeOnFirstMessageOnly: true, - GrpcServices: []*core.GrpcService{{ - TargetSpecifier: &core.GrpcService_EnvoyGrpc_{ - EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: "xds_cluster"}, - }, - }}, - }, - } - return source -} - -func GenerateSnapshot() cache.Snapshot { - return cache.NewSnapshot( - "1", - []types.Resource{}, // endpoints - []types.Resource{makeCluster(ClusterName)}, - []types.Resource{makeRoute(RouteName, ClusterName)}, - []types.Resource{makeHTTPListener(ListenerName, RouteName)}, - []types.Resource{}, // runtimes - []types.Resource{}, // secrets - []types.Resource{}, // extensions configs - ) -} diff --git a/examples/dynamic-config-cp/verify.sh b/examples/dynamic-config-cp/verify.sh deleted file mode 100755 index ed6747c24a22..000000000000 --- a/examples/dynamic-config-cp/verify.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -e - -export NAME=dynamic-config-cp -export UPARGS=" proxy" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Check port 10000 is not open (still shows as succeeded)" -nc -zv localhost 10000 |& grep -v open - -run_log "Check the static cluster" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].static_clusters' \ - | grep 'go-control-plane' - -run_log "Check there is no config for dynamic clusters" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters // "NO_CLUSTERS"' \ - | grep NO_CLUSTERS - -run_log "Bring up go-control-plane" -"${DOCKER_COMPOSE[@]}" up --build -d go-control-plane -wait_for 30 sh -c "${DOCKER_COMPOSE[*]} ps go-control-plane | grep healthy | grep -v unhealthy" -wait_for 10 bash -c "responds_with 'Request served by service1' http://localhost:10000" - -run_log "Check for response from service1 backend" -responds_with \ - "Request served by service1" \ - http://localhost:10000 - -run_log "Check config for active clusters" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"version_info": "1"' -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"address": "service1"' - -run_log "Bring down the control plane" -"${DOCKER_COMPOSE[@]}" stop go-control-plane - -wait_for 10 sh -c "\ - curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '\"version_info\": \"1\"'" - -run_log "Check for continued response from service1 backend" -responds_with \ - "Request served by service1" \ - http://localhost:10000 - -run_log "Check config for active clusters" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"version_info": "1"' -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"address": "service1"' - -run_log "Edit resource.go" -sed -i'.bak' s/service1/service2/ resource.go -sed -i'.bak2' s/\"1\",/\"2\",/ resource.go - -run_log "Bring back up the control plane" -"${DOCKER_COMPOSE[@]}" up --build -d go-control-plane -wait_for 30 sh -c "${DOCKER_COMPOSE[*]} ps go-control-plane | grep healthy | grep -v unhealthy" - -run_log "Check for response from service2 backend" -wait_for 5 bash -c "responds_with \ - 'Request served by service2' \ - http://localhost:10000" - -run_log "Check config for active clusters pointing to service2" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"version_info": "2"' -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"address": "service2"' - -mv resource.go.bak resource.go diff --git a/examples/dynamic-config-fs/README.md b/examples/dynamic-config-fs/README.md deleted file mode 100644 index 3cb1ed49d940..000000000000 --- a/examples/dynamic-config-fs/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/dynamic-configuration-filesystem.html). diff --git a/examples/dynamic-config-fs/_include/response-config-active-clusters-updated.json b/examples/dynamic-config-fs/_include/response-config-active-clusters-updated.json deleted file mode 100644 index 43b676e72d66..000000000000 --- a/examples/dynamic-config-fs/_include/response-config-active-clusters-updated.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "example_proxy_cluster", - "type": "LOGICAL_DNS", - "connect_timeout": "5s", - "dns_lookup_family": "V4_ONLY", - "load_assignment": { - "cluster_name": "example_proxy_cluster", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "service2", - "port_value": 8080 - } - } - } - } - ] - } - ] - } - }, - "last_updated": "2020-10-25T20:37:05.838Z" - } -] diff --git a/examples/dynamic-config-fs/_include/response-config-active-clusters.json b/examples/dynamic-config-fs/_include/response-config-active-clusters.json deleted file mode 100644 index 3813a9a9c56c..000000000000 --- a/examples/dynamic-config-fs/_include/response-config-active-clusters.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "cluster": { - "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", - "name": "example_proxy_cluster", - "type": "LOGICAL_DNS", - "connect_timeout": "5s", - "dns_lookup_family": "V4_ONLY", - "load_assignment": { - "cluster_name": "example_proxy_cluster", - "endpoints": [ - { - "lb_endpoints": [ - { - "endpoint": { - "address": { - "socket_address": { - "address": "service1", - "port_value": 8080 - } - } - } - } - ] - } - ] - } - }, - "last_updated": "2020-10-25T20:37:05.838Z" - } -] diff --git a/examples/dynamic-config-fs/configs/cds.yaml b/examples/dynamic-config-fs/configs/cds.yaml deleted file mode 100644 index 8cc9e3c0b26c..000000000000 --- a/examples/dynamic-config-fs/configs/cds.yaml +++ /dev/null @@ -1,13 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster - name: example_proxy_cluster - type: STRICT_DNS - load_assignment: - cluster_name: example_proxy_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8080 diff --git a/examples/dynamic-config-fs/configs/lds.yaml b/examples/dynamic-config-fs/configs/lds.yaml deleted file mode 100644 index ac12d349dffc..000000000000 --- a/examples/dynamic-config-fs/configs/lds.yaml +++ /dev/null @@ -1,28 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.config.listener.v3.Listener - name: listener_0 - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: example_proxy_cluster diff --git a/examples/dynamic-config-fs/docker-compose.yaml b/examples/dynamic-config-fs/docker-compose.yaml deleted file mode 100644 index 9734368cbf37..000000000000 --- a/examples/dynamic-config-fs/docker-compose.yaml +++ /dev/null @@ -1,23 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-dynamic-fs - depends_on: - - service1 - - service2 - ports: - - 10000:10000 - - 19000:19000 - - service1: - build: - context: ../shared/echo - hostname: service1 - - service2: - build: - context: ../shared/echo - hostname: service2 diff --git a/examples/dynamic-config-fs/envoy.yaml b/examples/dynamic-config-fs/envoy.yaml deleted file mode 100644 index d496dad71643..000000000000 --- a/examples/dynamic-config-fs/envoy.yaml +++ /dev/null @@ -1,17 +0,0 @@ -node: - id: id_1 - cluster: test - -dynamic_resources: - cds_config: - path_config_source: - path: /var/lib/envoy/cds.yaml - lds_config: - path_config_source: - path: /var/lib/envoy/lds.yaml - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 19000 diff --git a/examples/dynamic-config-fs/example.rst b/examples/dynamic-config-fs/example.rst deleted file mode 100644 index 4935cd5bbe6e..000000000000 --- a/examples/dynamic-config-fs/example.rst +++ /dev/null @@ -1,137 +0,0 @@ -.. _install_sandboxes_dynamic_config_fs: - -Dynamic configuration (filesystem) -================================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`jq ` - Parse ``json`` output from the upstream echo servers. - -This example walks through configuring Envoy using filesystem-based dynamic configuration. - -It demonstrates how configuration provided to Envoy dynamically can be updated without -restarting the server. - -Step 1: Start the proxy container -********************************* - -Change directory to ``examples/dynamic-config-fs`` in the Envoy repository. - -Build and start the containers. - -This should also start two upstream ``HTTP`` echo servers, ``service1`` and ``service2``. - -.. code-block:: console - - $ pwd - envoy/examples/dynamic-config-fs - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------ - dynamic-config-fs_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:19000->19000/tcp - dynamic-config-fs_service1_1 /bin/echo-server Up 8080/tcp - dynamic-config-fs_service2_1 /bin/echo-server Up 8080/tcp - -Step 2: Check web response -************************** - -You should be able to make a request to port ``10000``, which will be served by ``service1``. - -.. code-block:: console - - $ curl -s http://localhost:10000 - Request served by service1 - - HTTP/2.0 GET / - - Host: localhost:10000 - User-Agent: curl/7.72.0 - Accept: */* - X-Forwarded-Proto: http - X-Request-Id: 6672902d-56ca-456c-be6a-992a603cab9a - X-Envoy-Expected-Rq-Timeout-Ms: 15000 - -Step 3: Dump Envoy's ``dynamic_active_clusters`` config -******************************************************* - -If you now dump the proxy’s :ref:`dynamic_active_clusters ` -configuration, you should see it is configured with the ``example_proxy_cluster`` pointing to ``service1``. - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq -r '.configs[1].dynamic_active_clusters' - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-fs/_include/response-config-active-clusters.json - :language: json - :emphasize-lines: 10, 18-19 - -Step 4: Replace ``cds.yaml`` inside the container to update upstream cluster -**************************************************************************** - -The example setup provides Envoy with two dynamic configuration files: - -- :download:`configs/cds.yaml ` to provide a :ref:`Cluster - discovery service (CDS) `. -- :download:`configs/lds.yaml ` to provide a :ref:`Listener - discovery service (LDS) `. - -Edit ``cds.yaml`` inside the container and change the cluster address -from ``service1`` to ``service2``: - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-fs/configs/cds.yaml - :language: yaml - :linenos: - :lines: 6-13 - :lineno-start: 6 - :emphasize-lines: 7 - -You can do this using ``sed`` inside the container: - -.. code-block:: console - - docker compose exec -T proxy sed -i s/service1/service2/ /var/lib/envoy/cds.yaml - -.. note:: - - The above example uses ``sed -i``, which works as an inplace edit as ``sed`` does copy, edit and move in order to do this. - -Step 5: Check Envoy uses updated configuration -********************************************** - -Checking the web response again, the request should now be handled by ``service2``: - -.. code-block:: console - - $ curl http://localhost:10000 | grep "served by" - Request served by service2 - -Dumping the :ref:`dynamic_active_clusters `, -the ``example_proxy_cluster`` should now be configured to proxy to ``service2``: - -.. code-block:: console - - $ curl -s http://localhost:19000/config_dump | jq -r '.configs[1].dynamic_active_clusters' - -.. literalinclude:: /start/sandboxes/_include/dynamic-config-fs/_include/response-config-active-clusters-updated.json - :language: json - :emphasize-lines: 10, 18-19 - -.. seealso:: - - :ref:`Dynamic configuration (filesystem) quick start guide ` - Quick start guide to filesystem-based dynamic configuration of Envoy. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - :ref:`Dynamic configuration (control plane) sandbox ` - Configure Envoy dynamically with the Go Control Plane. diff --git a/examples/dynamic-config-fs/verify.sh b/examples/dynamic-config-fs/verify.sh deleted file mode 100755 index 476454ba1ac6..000000000000 --- a/examples/dynamic-config-fs/verify.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -export NAME=dynamic-config-fs - -chmod go+r configs/* -chmod go+rx configs - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Check for response comes from service1 upstream" -responds_with \ - "Request served by service1" \ - http://localhost:10000 - -run_log "Check config for active clusters pointing to service1" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"address": "service1"' - -run_log "Set upstream to service2" -"${DOCKER_COMPOSE[@]}" exec -T proxy sed -i s/service1/service2/ /var/lib/envoy/cds.yaml -wait_for 10 bash -c "responds_with 'Request served by service2' http://localhost:10000" - -run_log "Check for response comes from service2 upstream" -responds_with \ - "Request served by service2" \ - http://localhost:10000 - -run_log "Check config for active clusters pointing to service2" -curl -s http://localhost:19000/config_dump \ - | jq -r '.configs[1].dynamic_active_clusters' \ - | grep '"address": "service2"' diff --git a/examples/ext_authz/.env b/examples/ext_authz/.env deleted file mode 100644 index 0a7d4cb0eaf0..000000000000 --- a/examples/ext_authz/.env +++ /dev/null @@ -1 +0,0 @@ -FRONT_ENVOY_YAML=config/grpc-service/v3.yaml diff --git a/examples/ext_authz/Dockerfile-opa b/examples/ext_authz/Dockerfile-opa deleted file mode 100644 index 463bca657f15..000000000000 --- a/examples/ext_authz/Dockerfile-opa +++ /dev/null @@ -1 +0,0 @@ -FROM openpolicyagent/opa:0.67.0-istio@sha256:41512cb576ba71c2a7267a64958f9f866d549fd681792eac1679cccd3f8b0276 diff --git a/examples/ext_authz/README.md b/examples/ext_authz/README.md deleted file mode 100644 index c0a121144d07..000000000000 --- a/examples/ext_authz/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/ext_authz) diff --git a/examples/ext_authz/auth/grpc-service/Makefile b/examples/ext_authz/auth/grpc-service/Makefile deleted file mode 100644 index e9ee1e9581cf..000000000000 --- a/examples/ext_authz/auth/grpc-service/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: server - -server: - @CGO_ENABLED=0 GOOS=linux go build -a --ldflags '-extldflags "-static"' \ - -tags "netgo" -installsuffix netgo \ - -o server -clean: - @rm -fr server diff --git a/examples/ext_authz/auth/grpc-service/go.mod b/examples/ext_authz/auth/grpc-service/go.mod deleted file mode 100644 index ae97c30f021b..000000000000 --- a/examples/ext_authz/auth/grpc-service/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module github.com/envoyproxy/envoy/examples/ext_authz/auth/grpc-service - -go 1.21 - -toolchain go1.22.5 - -require ( - github.com/envoyproxy/go-control-plane v0.12.0 - github.com/golang/protobuf v1.5.4 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 - google.golang.org/grpc v1.65.0 -) - -require ( - github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect - github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect -) diff --git a/examples/ext_authz/auth/grpc-service/go.sum b/examples/ext_authz/auth/grpc-service/go.sum deleted file mode 100644 index 0af3b63c8b48..000000000000 --- a/examples/ext_authz/auth/grpc-service/go.sum +++ /dev/null @@ -1,22 +0,0 @@ -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw= -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/examples/ext_authz/auth/grpc-service/main.go b/examples/ext_authz/auth/grpc-service/main.go deleted file mode 100644 index bbfaf9a989d6..000000000000 --- a/examples/ext_authz/auth/grpc-service/main.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net" - - envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" - "google.golang.org/grpc" - - "github.com/envoyproxy/envoy/examples/ext_authz/auth/grpc-service/pkg/auth" - auth_v3 "github.com/envoyproxy/envoy/examples/ext_authz/auth/grpc-service/pkg/auth/v3" -) - -func main() { - port := flag.Int("port", 9001, "gRPC port") - data := flag.String("users", "../../users.json", "users file") - - flag.Parse() - - lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) - if err != nil { - log.Fatalf("failed to listen to %d: %v", *port, err) - } - - users, err := auth.LoadUsers(*data) - if err != nil { - log.Fatalf("failed to load user data:%s %v", *data, err) - } - gs := grpc.NewServer() - - envoy_service_auth_v3.RegisterAuthorizationServer(gs, auth_v3.New(users)) - - log.Printf("starting gRPC server on: %d\n", *port) - - gs.Serve(lis) -} diff --git a/examples/ext_authz/auth/grpc-service/pkg/auth/users.go b/examples/ext_authz/auth/grpc-service/pkg/auth/users.go deleted file mode 100644 index 507c3560bdf1..000000000000 --- a/examples/ext_authz/auth/grpc-service/pkg/auth/users.go +++ /dev/null @@ -1,32 +0,0 @@ -package auth - -import ( - "encoding/json" - "io/ioutil" -) - -// Users holds a list of users. -type Users map[string]string - -// Check checks if a key could retrieve a user from a list of users. -func (u Users) Check(key string) (bool, string) { - value, ok := u[key] - if !ok { - return false, "" - } - return ok, value -} - -// LoadUsers load users data from a JSON file. -func LoadUsers(jsonFile string) (Users, error) { - var users Users - data, err := ioutil.ReadFile(jsonFile) - if err != nil { - return nil, err - } - - if err := json.Unmarshal(data, &users); err != nil { - return nil, err - } - return users, nil -} diff --git a/examples/ext_authz/auth/grpc-service/pkg/auth/v3/auth.go b/examples/ext_authz/auth/grpc-service/pkg/auth/v3/auth.go deleted file mode 100644 index 1cae7cbd8d43..000000000000 --- a/examples/ext_authz/auth/grpc-service/pkg/auth/v3/auth.go +++ /dev/null @@ -1,68 +0,0 @@ -package v3 - -import ( - "context" - "log" - "strings" - - envoy_api_v3_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" - envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" - "github.com/golang/protobuf/ptypes/wrappers" - "google.golang.org/genproto/googleapis/rpc/code" - "google.golang.org/genproto/googleapis/rpc/status" - - "github.com/envoyproxy/envoy/examples/ext_authz/auth/grpc-service/pkg/auth" -) - -type server struct { - users auth.Users -} - -var _ envoy_service_auth_v3.AuthorizationServer = &server{} - -// New creates a new authorization server. -func New(users auth.Users) envoy_service_auth_v3.AuthorizationServer { - return &server{users} -} - -// Check implements authorization's Check interface which performs authorization check based on the -// attributes associated with the incoming request. -func (s *server) Check( - ctx context.Context, - req *envoy_service_auth_v3.CheckRequest) (*envoy_service_auth_v3.CheckResponse, error) { - authorization := req.Attributes.Request.Http.Headers["authorization"] - log.Println(authorization) - - extracted := strings.Fields(authorization) - if len(extracted) == 2 && extracted[0] == "Bearer" { - valid, user := s.users.Check(extracted[1]) - if valid { - return &envoy_service_auth_v3.CheckResponse{ - HttpResponse: &envoy_service_auth_v3.CheckResponse_OkResponse{ - OkResponse: &envoy_service_auth_v3.OkHttpResponse{ - Headers: []*envoy_api_v3_core.HeaderValueOption{ - { - Append: &wrappers.BoolValue{Value: false}, - Header: &envoy_api_v3_core.HeaderValue{ - // For a successful request, the authorization server sets the - // x-current-user value. - Key: "x-current-user", - Value: user, - }, - }, - }, - }, - }, - Status: &status.Status{ - Code: int32(code.Code_OK), - }, - }, nil - } - } - - return &envoy_service_auth_v3.CheckResponse{ - Status: &status.Status{ - Code: int32(code.Code_PERMISSION_DENIED), - }, - }, nil -} diff --git a/examples/ext_authz/auth/http-service/server.js b/examples/ext_authz/auth/http-service/server.js deleted file mode 100644 index 9c890d75226a..000000000000 --- a/examples/ext_authz/auth/http-service/server.js +++ /dev/null @@ -1,29 +0,0 @@ -const Http = require("http"); -const path = require("path"); - -const tokens = require(process.env.USERS || - path.join(__dirname, "..", "users.json")); - -const server = new Http.Server((req, res) => { - const authorization = req.headers["authorization"] || ""; - const extracted = authorization.split(" "); - if (extracted.length === 2 && extracted[0] === "Bearer") { - const user = checkToken(extracted[1]); - if (user !== undefined) { - // The authorization server returns a response with "x-current-user" header for a successful - // request. - res.writeHead(200, { "x-current-user": user }); - return res.end(); - } - } - res.writeHead(403); - res.end(); -}); - -const port = process.env.PORT || 9002; -server.listen(port); -console.log(`starting HTTP server on: ${port}`); - -function checkToken(token) { - return tokens[token]; -} diff --git a/examples/ext_authz/auth/users.json b/examples/ext_authz/auth/users.json deleted file mode 100644 index 4068bcb7628e..000000000000 --- a/examples/ext_authz/auth/users.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "token1": "user1", - "token2": "user2", - "token3": "user3" -} diff --git a/examples/ext_authz/config/grpc-service/v3.yaml b/examples/ext_authz/config/grpc-service/v3.yaml deleted file mode 100644 index 166e501c689c..000000000000 --- a/examples/ext_authz/config/grpc-service/v3.yaml +++ /dev/null @@ -1,67 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: upstream - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: upstream-service - http_filters: - - name: envoy.filters.http.ext_authz - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz - grpc_service: - envoy_grpc: - cluster_name: ext_authz-grpc-service - timeout: 0.250s - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: upstream-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: upstream-service - port_value: 8080 - - - name: ext_authz-grpc-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: ext_authz-grpc-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: ext_authz-grpc-service - port_value: 9001 diff --git a/examples/ext_authz/config/http-service.yaml b/examples/ext_authz/config/http-service.yaml deleted file mode 100644 index a1b7f18c1406..000000000000 --- a/examples/ext_authz/config/http-service.yaml +++ /dev/null @@ -1,67 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: upstream - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: upstream-service - http_filters: - - name: envoy.filters.http.ext_authz - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz - http_service: - server_uri: - uri: ext_authz - cluster: ext_authz-http-service - timeout: 0.250s - authorization_response: - allowed_upstream_headers: - patterns: - - exact: x-current-user - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: upstream-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: upstream-service - port_value: 8080 - - - name: ext_authz-http-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: ext_authz-http-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: ext_authz-http-service - port_value: 9002 diff --git a/examples/ext_authz/config/opa-service/policy.rego b/examples/ext_authz/config/opa-service/policy.rego deleted file mode 100644 index 484f01923c22..000000000000 --- a/examples/ext_authz/config/opa-service/policy.rego +++ /dev/null @@ -1,13 +0,0 @@ -package envoy.authz - -import input.attributes.request.http as http_request - -default allow = false - -allow = response { - http_request.method == "GET" - response := { - "allowed": true, - "headers": {"x-current-user": "OPA"} - } -} diff --git a/examples/ext_authz/config/opa-service/v3.yaml b/examples/ext_authz/config/opa-service/v3.yaml deleted file mode 100644 index 824239d4fd5f..000000000000 --- a/examples/ext_authz/config/opa-service/v3.yaml +++ /dev/null @@ -1,67 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: upstream - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: upstream-service - http_filters: - - name: envoy.filters.http.ext_authz - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz - grpc_service: - envoy_grpc: - cluster_name: ext_authz-opa-service - timeout: 0.250s - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: upstream-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: upstream-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: upstream-service - port_value: 8080 - - - name: ext_authz-opa-service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: ext_authz-opa-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: ext_authz-opa-service - port_value: 9002 diff --git a/examples/ext_authz/docker-compose.yaml b/examples/ext_authz/docker-compose.yaml deleted file mode 100644 index 3bf74828b5b8..000000000000 --- a/examples/ext_authz/docker-compose.yaml +++ /dev/null @@ -1,55 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-ext_authz - args: - ENVOY_CONFIG: config/http-service.yaml - depends_on: - upstream-service: - condition: service_healthy - environment: - - FRONT_ENVOY_YAML - ports: - - "${PORT_PROXY:-8000}:8000" - - ext_authz-http-service: - build: - context: ./auth - dockerfile: ../../shared/node/Dockerfile - target: node-http-auth - volumes: - - ./users.json:/etc/users.json - environment: - - USERS=/etc/users.json - - ext_authz-grpc-service: - build: - context: auth - dockerfile: ../../shared/golang/Dockerfile - target: golang-grpc-auth - volumes: - - ./users.json:/etc/users.json - - ext_authz-opa-service: - build: - context: . - dockerfile: Dockerfile-opa - volumes: - - ./config/opa-service/policy.rego:/etc/policy.rego - command: - - run - - --server - - --log-format=json-pretty - - --set=plugins.envoy_ext_authz_grpc.addr=:9002 - - --set=decision_logs.console=true - - /etc/policy.rego - - upstream-service: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - ./upstream/service/service.py:/code/service.py diff --git a/examples/ext_authz/example.rst b/examples/ext_authz/example.rst deleted file mode 100644 index 81b6460234c2..000000000000 --- a/examples/ext_authz/example.rst +++ /dev/null @@ -1,234 +0,0 @@ -.. _install_sandboxes_ext_authz: - -External authorization (``ext_authz``) filter -============================================= - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -The External Authorization sandbox demonstrates Envoy's :ref:`ext_authz filter ` -capability to delegate authorization of incoming requests through Envoy to an external services. - -While ext_authz can also be employed as a network filter, this sandbox is limited to exhibit -ext_authz HTTP Filter, which supports to call HTTP or gRPC service. - -The setup of this sandbox is very similar to front-proxy deployment, however calls to upstream -service behind the proxy will be checked by an external HTTP or gRPC service. In this sandbox, -for every authorized call, the external authorization service adds additional ``x-current-user`` -header entry to the original request headers to be forwarded to the upstream service. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/ext_authz`` directory. - -To build this sandbox example and start the example services, run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/ext_authz - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - -------------------------------------------------------------------------------------------------------------------- - ext_authz_ext_authz-grpc-service_1 /app/server -users /etc/us Up - ext_authz_ext_authz-http-service_1 docker-entrypoint.sh node Up - ext_authz_front-envoy_1 /docker-entrypoint.sh /bin Up 10000/tcp, 0.0.0.0:8000->8000/tcp - ext_authz_upstream-service_1 python3 /code/service.py Up (healthy) - -.. note:: - - This sandbox has multiple setup controlled by ``FRONT_ENVOY_YAML`` environment variable which - points to the effective Envoy configuration to be used. The default value of ``FRONT_ENVOY_YAML`` - can be defined in the ``.env`` file or provided inline when running the ``docker compose up`` - command. - - For more information, please take a look at - `environment variables in Compose documentation `_. - -By default, ``FRONT_ENVOY_YAML`` points to :download:`config/grpc-service/v3.yaml <_include/ext_authz/config/grpc-service/v3.yaml>` -file which bootstraps front-envoy with ext_authz HTTP filter with gRPC service ``V3`` (this is specified by -:ref:`transport_api_version field`). - -The possible values of ``FRONT_ENVOY_YAML`` can be found inside the ``config`` -directory. - -For example, to run Envoy with ext_authz HTTP filter with HTTP service will be: - -.. code-block:: console - - $ pwd - envoy/examples/ext_authz - $ docker compose pull - $ # Tearing down the currently running setup - $ docker compose down - $ FRONT_ENVOY_YAML=config/http-service.yaml docker compose up --build -d - $ # Or you can update the .env file with the above FRONT_ENVOY_YAML value, so you don't have to specify it when running the "up" command. - -Step 4: Access the upstream-service behind the Front Envoy -********************************************************** - -You can now try to send a request to upstream-service via the front-envoy as follows: - -.. code-block:: console - - $ curl -v localhost:8000/service - * Trying 127.0.0.1... - * TCP_NODELAY set - * Connected to localhost (127.0.0.1) port 8000 (#0) - > GET /service HTTP/1.1 - > Host: localhost:8000 - > User-Agent: curl/7.58.0 - > Accept: */* - > - < HTTP/1.1 403 Forbidden - < date: Fri, 19 Jun 2020 15:02:24 GMT - < server: envoy - < content-length: 0 - -As observed, the request failed with ``403 Forbidden`` status code. This happened since the ext_authz -filter employed by Envoy rejected the call. To let the request reach the upstream service, you need -to provide a ``Bearer`` token via the ``Authorization`` header. - -.. note:: - - A complete list of users is defined in :download:`auth/users.json <_include/ext_authz/auth/users.json>` - file. For example, the ``token1`` used in the below example is corresponding to ``user1``. - -An example of successful requests can be observed as follows: - -.. code-block:: console - - $ curl -v -H "Authorization: Bearer token1" localhost:8000/service - * Trying 127.0.0.1... - * TCP_NODELAY set - * Connected to localhost (127.0.0.1) port 8000 (#0) - > GET /service HTTP/1.1 - > Host: localhost:8000 - > User-Agent: curl/7.58.0 - > Accept: */* - > Authorization: Bearer token1 - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 24 - < server: envoy - < date: Fri, 19 Jun 2020 15:04:29 GMT - < x-envoy-upstream-service-time: 2 - < - * Connection #0 to host localhost left intact - Hello user1 from behind Envoy! - -We can also employ `Open Policy Agent `_ server -(with `envoy_ext_authz_grpc `_ plugin enabled) -as the authorization server. To run this example: - -.. code-block:: console - - $ pwd - envoy/examples/ext_authz - $ docker compose pull - $ # Tearing down the currently running setup - $ docker compose down - $ FRONT_ENVOY_YAML=config/opa-service/v3.yaml docker compose up --build -d - -And sending a request to the upstream service (via the Front Envoy) gives: - -.. code-block:: console - - $ curl localhost:8000/service --verbose - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8000 (#0) - > GET /service HTTP/1.1 - > Host: localhost:8000 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 28 - < server: envoy - < date: Thu, 02 Jul 2020 06:29:58 GMT - < x-envoy-upstream-service-time: 2 - < - * Connection #0 to host localhost left intact - Hello OPA from behind Envoy! - -From the logs, we can observe the policy decision message from the Open Policy Agent server (for -the above request against the defined policy in -:download:`config/opa-service/policy.rego <_include/ext_authz/config/opa-service/policy.rego>`): - -.. code-block:: console - - $ docker compose logs ext_authz-opa-service | grep decision_id -A 30 - ext_authz-opa-service_1 | "decision_id": "8143ca68-42d8-43e6-ade6-d1169bf69110", - ext_authz-opa-service_1 | "input": { - ext_authz-opa-service_1 | "attributes": { - ext_authz-opa-service_1 | "destination": { - ext_authz-opa-service_1 | "address": { - ext_authz-opa-service_1 | "Address": { - ext_authz-opa-service_1 | "SocketAddress": { - ext_authz-opa-service_1 | "PortSpecifier": { - ext_authz-opa-service_1 | "PortValue": 8000 - ext_authz-opa-service_1 | }, - ext_authz-opa-service_1 | "address": "172.28.0.6" - ext_authz-opa-service_1 | } - ext_authz-opa-service_1 | } - ext_authz-opa-service_1 | } - ext_authz-opa-service_1 | }, - ext_authz-opa-service_1 | "metadata_context": {}, - ext_authz-opa-service_1 | "request": { - ext_authz-opa-service_1 | "http": { - ext_authz-opa-service_1 | "headers": { - ext_authz-opa-service_1 | ":authority": "localhost:8000", - ext_authz-opa-service_1 | ":method": "GET", - ext_authz-opa-service_1 | ":path": "/service", - ext_authz-opa-service_1 | "accept": "*/*", - ext_authz-opa-service_1 | "user-agent": "curl/7.64.1", - ext_authz-opa-service_1 | "x-forwarded-proto": "http", - ext_authz-opa-service_1 | "x-request-id": "b77919c0-f1d4-4b06-b444-5a8b32d5daf4" - ext_authz-opa-service_1 | }, - ext_authz-opa-service_1 | "host": "localhost:8000", - ext_authz-opa-service_1 | "id": "16617514055874272263", - ext_authz-opa-service_1 | "method": "GET", - ext_authz-opa-service_1 | "path": "/service", - -Trying to send a request with method other than ``GET`` gives a rejection: - -.. code-block:: console - - $ curl -X POST localhost:8000/service --verbose - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8000 (#0) - > PUT /service HTTP/1.1 - > Host: localhost:8000 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 403 Forbidden - < date: Thu, 02 Jul 2020 06:46:13 GMT - < server: envoy - < content-length: 0 - -.. seealso:: - - :ref:`ext_authz filter ` - Learn more about using Envoy's ``ext_authz`` filter. - - `Open Policy Agent `_ - Policy-based control for cloud native environments. - - `envoy_ext_authz_grpc `_ - Open Policy Agent Envoy plugin. - - `environment variables in Compose documentation `_. - Further information about using env variables with Docker Compose. diff --git a/examples/ext_authz/run_envoy.sh b/examples/ext_authz/run_envoy.sh deleted file mode 100755 index c9bb7ca58b4d..000000000000 --- a/examples/ext_authz/run_envoy.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/local/bin/envoy -c "/etc/envoy-${FRONT_ENVOY_YAML}" --service-cluster front-proxy diff --git a/examples/ext_authz/upstream/service/service.py b/examples/ext_authz/upstream/service/service.py deleted file mode 100644 index 6bbf828f6cde..000000000000 --- a/examples/ext_authz/upstream/service/service.py +++ /dev/null @@ -1,14 +0,0 @@ -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/service") -async def get(request): - return web.Response(text=f"Hello {request.headers.get('x-current-user')} from behind Envoy!") - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/ext_authz/users.json b/examples/ext_authz/users.json deleted file mode 100644 index 4068bcb7628e..000000000000 --- a/examples/ext_authz/users.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "token1": "user1", - "token2": "user2", - "token3": "user3" -} diff --git a/examples/ext_authz/verify.sh b/examples/ext_authz/verify.sh deleted file mode 100755 index c2e8699f64c3..000000000000 --- a/examples/ext_authz/verify.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e - -export NAME=ext_authz -export PORT_PROXY="${EXT_AUTH_PORT_PROXY:-10500}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test services responds with 403" -responds_with_header \ - "HTTP/1.1 403 Forbidden"\ - "http://localhost:${PORT_PROXY}/service" - -run_log "Restart front-envoy with FRONT_ENVOY_YAML=config/http-service.yaml" -"${DOCKER_COMPOSE[@]}" down -FRONT_ENVOY_YAML=config/http-service.yaml "${DOCKER_COMPOSE[@]}" up -d - -wait_for 15 bash -c "\ - responds_with_header \ - 'HTTP/1.1 200 OK' \ - -H 'Authorization: Bearer token1' \ - http://localhost:${PORT_PROXY}/service" - -run_log "Test service responds with 403" -responds_with_header \ - "HTTP/1.1 403 Forbidden"\ - "http://localhost:${PORT_PROXY}/service" - -run_log "Test authenticated service responds with 200" -responds_with_header \ - "HTTP/1.1 200 OK" \ - -H "Authorization: Bearer token1" \ - "http://localhost:${PORT_PROXY}/service" - -run_log "Restart front-envoy with FRONT_ENVOY_YAML=config/opa-service/v3.yaml" -"${DOCKER_COMPOSE[@]}" down -FRONT_ENVOY_YAML=config/opa-service/v3.yaml "${DOCKER_COMPOSE[@]}" up -d -wait_for 15 bash -c "\ - responds_with_header \ - 'HTTP/1.1 200 OK' \ - http://localhost:${PORT_PROXY}/service" - -run_log "Test OPA service responds with 200" -responds_with_header \ - "HTTP/1.1 200 OK" \ - "http://localhost:${PORT_PROXY}/service" - -run_log "Check OPA logs" -"${DOCKER_COMPOSE[@]}" logs ext_authz-opa-service | grep decision_id -A 30 - -run_log "Check OPA service rejects POST" -responds_with_header \ - "HTTP/1.1 403 Forbidden" \ - -X POST \ - "http://localhost:${PORT_PROXY}/service" diff --git a/examples/fault-injection/.gitignore b/examples/fault-injection/.gitignore deleted file mode 100644 index a2ac47b60d6e..000000000000 --- a/examples/fault-injection/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/runtime/ diff --git a/examples/fault-injection/Dockerfile-backend b/examples/fault-injection/Dockerfile-backend deleted file mode 100644 index 0fdf28a41af1..000000000000 --- a/examples/fault-injection/Dockerfile-backend +++ /dev/null @@ -1 +0,0 @@ -FROM kennethreitz/httpbin@sha256:599fe5e5073102dbb0ee3dbb65f049dab44fa9fc251f6835c9990f8fb196a72b diff --git a/examples/fault-injection/README.md b/examples/fault-injection/README.md deleted file mode 100644 index bda89392fb87..000000000000 --- a/examples/fault-injection/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/fault_injection.html). diff --git a/examples/fault-injection/disable_abort_fault_injection.sh b/examples/fault-injection/disable_abort_fault_injection.sh deleted file mode 100755 index bfbc949eb8fa..000000000000 --- a/examples/fault-injection/disable_abort_fault_injection.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -ex - -rm /srv/runtime/v1/envoy/fault/http/abort/abort_percent -rm /srv/runtime/v1/envoy/fault/http/abort/http_status - -pushd /srv/runtime -ln -s /srv/runtime/v1 new && mv -Tf new current -popd diff --git a/examples/fault-injection/disable_delay_fault_injection.sh b/examples/fault-injection/disable_delay_fault_injection.sh deleted file mode 100755 index 72c84f90b71b..000000000000 --- a/examples/fault-injection/disable_delay_fault_injection.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -ex - -rm /srv/runtime/v1/envoy/fault/http/delay/fixed_delay_percent -rm /srv/runtime/v1/envoy/fault/http/delay/fixed_duration_ms - -pushd /srv/runtime -ln -s /srv/runtime/v1 new && mv -Tf new current -popd diff --git a/examples/fault-injection/docker-compose.yaml b/examples/fault-injection/docker-compose.yaml deleted file mode 100644 index f31ad11fcf6d..000000000000 --- a/examples/fault-injection/docker-compose.yaml +++ /dev/null @@ -1,17 +0,0 @@ -services: - envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-fault-injection - volumes: - - ./runtime:/srv/runtime - ports: - - 9211:9211 - - backend: - build: - context: . - dockerfile: Dockerfile-backend - ports: - - ${PORT_PROXY:-8080}:80 diff --git a/examples/fault-injection/enable_abort_fault_injection.sh b/examples/fault-injection/enable_abort_fault_injection.sh deleted file mode 100755 index ff587a093770..000000000000 --- a/examples/fault-injection/enable_abort_fault_injection.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -ex - -mkdir -p /srv/runtime/v1/envoy/fault/http/abort -echo '100' > /srv/runtime/v1/envoy/fault/http/abort/abort_percent -echo '503' > /srv/runtime/v1/envoy/fault/http/abort/http_status - -pushd /srv/runtime -ln -s /srv/runtime/v1 new && mv -Tf new current -popd diff --git a/examples/fault-injection/enable_delay_fault_injection.sh b/examples/fault-injection/enable_delay_fault_injection.sh deleted file mode 100755 index 09740d17fcb0..000000000000 --- a/examples/fault-injection/enable_delay_fault_injection.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -ex - -mkdir -p /srv/runtime/v1/envoy/fault/http/delay -echo '50' > /srv/runtime/v1/envoy/fault/http/delay/fixed_delay_percent -echo '3000' > /srv/runtime/v1/envoy/fault/http/delay/fixed_duration_ms - -pushd /srv/runtime -ln -s /srv/runtime/v1 new && mv -Tf new current -popd diff --git a/examples/fault-injection/envoy.yaml b/examples/fault-injection/envoy.yaml deleted file mode 100644 index 697fd2957960..000000000000 --- a/examples/fault-injection/envoy.yaml +++ /dev/null @@ -1,64 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 9211 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: service - domains: - - "*" - routes: - - match: - prefix: / - route: - cluster: local_service - http_filters: - - name: envoy.filters.http.fault - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault - abort: - http_status: 503 - percentage: - numerator: 0 - denominator: HUNDRED - delay: - fixed_delay: 3s - percentage: - numerator: 0 - denominator: HUNDRED - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: local_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend - port_value: 80 -layered_runtime: - layers: - - name: disk_layer_0 - disk_layer: - symlink_root: /srv/runtime/current - subdirectory: envoy diff --git a/examples/fault-injection/example.rst b/examples/fault-injection/example.rst deleted file mode 100644 index a30c96f856b1..000000000000 --- a/examples/fault-injection/example.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. _install_sandboxes_fault_injection: - -Fault injection filter -====================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -This simple example demonstrates Envoy's :ref:`fault injection ` capability -using Envoy's :ref:`runtime support ` to control the feature. - -It demonstrates fault injection that cause the request to abort and fail, and also faults that simply delay the -response. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/fault_injection`` directory. - -Terminal 1 - -.. code-block:: console - - $ pwd - envoy/examples/fault-injection - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------ - fault-injection_backend_1 gunicorn -b 0.0.0.0:80 htt Up 0.0.0.0:8080->80/tcp - fault-injection_envoy_1 /docker-entrypoint.sh /usr Up 10000/tcp, 0.0.0.0:9211->9211/tcp - -Step 2: Start sending continuous stream of HTTP requests -******************************************************** - -Terminal 2 - -.. code-block:: console - - $ pwd - envoy/examples/fault-injection - $ docker compose exec envoy bash - $ bash send_request.sh - -The script above (:download:`send_request.sh <_include/fault-injection/send_request.sh>`) sends a continuous stream -of HTTP requests to Envoy, which in turn forwards the requests to the backend container. - -Fault injection is configured in Envoy but turned off (i.e. affects 0% of requests). - -Consequently, you should see a continuous sequence of ``HTTP 200`` response codes. - -Step 3: Test Envoy's abort fault injection -****************************************** - -Turn on *abort* fault injection via the runtime using the commands below. - -Terminal 3 - -.. code-block:: console - - $ docker compose exec envoy bash - $ bash enable_abort_fault_injection.sh - -The script above enables ``HTTP`` aborts for 100% of requests. - -You should now see a continuous sequence of ``HTTP 503`` responses for all requests. - -To disable the abort injection: - -Terminal 3 - -.. code-block:: console - - $ bash disable_abort_fault_injection.sh - -Step 4: Test Envoy's delay fault injection -****************************************** - -Turn on *delay* fault injection via the runtime using the commands below. - -Terminal 3 - -.. code-block:: console - - $ docker compose exec envoy bash - $ bash enable_delay_fault_injection.sh - -The script above will add a 3-second delay to 50% of ``HTTP`` requests. - -You should now see a continuous sequence of ``HTTP 200`` responses for all requests, but half of the requests -will take 3 seconds to complete. - -To disable the delay injection: - -Terminal 3 - -.. code-block:: console - - $ bash disable_delay_fault_injection.sh - -Step 5: Check the current runtime filesystem -******************************************** - -To see the current runtime filesystem overview: - -Terminal 3 - -.. code-block:: console - - $ tree /srv/runtime - -.. seealso:: - - :ref:`Fault injection ` - Learn more about Envoy's ``HTTP`` fault injection filter. diff --git a/examples/fault-injection/send_request.sh b/examples/fault-injection/send_request.sh deleted file mode 100755 index 9a10435664c2..000000000000 --- a/examples/fault-injection/send_request.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -ex - -while :; do - curl -v localhost:9211/status/200 - sleep 1 -done diff --git a/examples/fault-injection/verify.sh b/examples/fault-injection/verify.sh deleted file mode 100755 index a6af1cb1d420..000000000000 --- a/examples/fault-injection/verify.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -e - -export NAME=fault-injection -export PORT_PROXY="${FAULT_INJECTION_PORT_PROXY:-10610}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Send requests for 20 seconds" -"${DOCKER_COMPOSE[@]}" exec -T envoy bash -c \ - "bash send_request.sh & export pid=\$! && sleep 20 && kill \$pid" \ - &> /dev/null - -run_log "Check logs" -"${DOCKER_COMPOSE[@]}" logs | grep "HTTP/1.1\" 200" - - -_fault_injection_test () { - local action code existing_200s existing_codes - action="$1" - code="$2" - existing_codes=0 - - # enable fault injection and check for http hits of type $code - existing_codes=$("${DOCKER_COMPOSE[@]}" logs | grep -c "HTTP/1.1\" ${code}" || :) - run_log "Enable ${action} fault injection" - "${DOCKER_COMPOSE[@]}" exec -T envoy bash "enable_${action}_fault_injection.sh" - run_log "Send requests for 20 seconds" - "${DOCKER_COMPOSE[@]}" exec -T envoy bash -c \ - "bash send_request.sh & export pid=\$! && sleep 20 && kill \$pid" \ - &> /dev/null - run_log "Check logs again" - new_codes=$("${DOCKER_COMPOSE[@]}" logs | grep -c "HTTP/1.1\" ${code}") - if [[ "$new_codes" -le "$existing_codes" ]]; then - echo "ERROR: expected to find new logs with response code $code" >&2 - return 1 - fi - - # disable fault injection and check for http hits of type 200 - existing_200s=$("${DOCKER_COMPOSE[@]}" logs | grep -c "HTTP/1.1\" 200") - run_log "Disable ${action} fault injection" - "${DOCKER_COMPOSE[@]}" exec -T envoy bash "disable_${action}_fault_injection.sh" - run_log "Send requests for 20 seconds" - "${DOCKER_COMPOSE[@]}" exec -T envoy bash -c \ - "bash send_request.sh & export pid=\$! && sleep 20 && kill \$pid" \ - &> /dev/null - run_log "Check logs again" - new_200s=$("${DOCKER_COMPOSE[@]}" logs | grep -c "HTTP/1.1\" 200") - if [[ "$new_200s" -le "$existing_200s" ]]; then - echo "ERROR: expected to find new logs with response code 200" >&2 - return 1 - fi -} - -_fault_injection_test abort 503 -_fault_injection_test delay 200 - -run_log "Check tree" -"${DOCKER_COMPOSE[@]}" exec -T envoy tree /srv/runtime diff --git a/examples/front-proxy/README.md b/examples/front-proxy/README.md deleted file mode 100644 index 95dd5abd42bb..000000000000 --- a/examples/front-proxy/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/front_proxy.html) diff --git a/examples/front-proxy/docker-compose.yaml b/examples/front-proxy/docker-compose.yaml deleted file mode 100644 index 641097d9bbc5..000000000000 --- a/examples/front-proxy/docker-compose.yaml +++ /dev/null @@ -1,54 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - service-envoy-1: - condition: service_healthy - service-envoy-2: - condition: service_healthy - ports: - - "${PORT_PROXY:-8080}:8080" - - "${PORT_HTTPS:-8443}:8443" - - "${PORT_STATS:-8001}:8001" - - service-envoy-1: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-admin - args: - ENVOY_CONFIG: ./service-envoy.yaml - ENVOY_ADMIN_PORT: 8001 - depends_on: - service1: - condition: service_healthy - - service1: - build: - context: ../shared/python - target: aiohttp-tracing-service2 - environment: - - SERVICE_NAME=1 - - service-envoy-2: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-admin - args: - ENVOY_ADMIN_PORT: 8001 - ENVOY_CONFIG: ./service-envoy-2.yaml - - depends_on: - service2: - condition: service_healthy - - service2: - build: - context: ../shared/python - target: aiohttp-tracing-service2 - environment: - - SERVICE_NAME=2 diff --git a/examples/front-proxy/envoy.yaml b/examples/front-proxy/envoy.yaml deleted file mode 100644 index 3eb5d0e0b74d..000000000000 --- a/examples/front-proxy/envoy.yaml +++ /dev/null @@ -1,168 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8080 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1-envoy - - match: - prefix: "/service/2" - route: - cluster: service2-envoy - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - - address: - socket_address: - address: 0.0.0.0 - port_value: 8443 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1-envoy - - match: - prefix: "/service/2" - route: - cluster: service2-envoy - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: service1-envoy - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1-envoy - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-envoy-1 - port_value: 8000 - - name: service2-envoy - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2-envoy - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-envoy-2 - port_value: 8000 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 -layered_runtime: - layers: - - name: static_layer_0 - static_layer: - envoy: - resource_limits: - listener: - example_listener_name: - connection_limit: 10000 diff --git a/examples/front-proxy/example.rst b/examples/front-proxy/example.rst deleted file mode 100644 index 5611ad5301c3..000000000000 --- a/examples/front-proxy/example.rst +++ /dev/null @@ -1,333 +0,0 @@ -.. _install_sandboxes_front_proxy: - -Front proxy -=========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -To get a flavor of what Envoy has to offer as a front proxy, we are releasing a -`docker compose `_ sandbox that deploys a front Envoy and a -couple of services (simple ``aiohttp`` apps) colocated with a running service Envoy. - -The three containers will be deployed inside a virtual network called ``envoymesh``. - -Below you can see a graphic showing the docker compose deployment: - -.. image:: /_static/docker_compose_front_proxy.svg - :width: 100% - -All incoming requests are routed via the front Envoy, which is acting as a reverse proxy sitting on -the edge of the ``envoymesh`` network. Port ``8080``, ``8443``, and ``8001`` are exposed by docker -compose (see :download:`docker-compose.yaml <_include/front-proxy/docker-compose.yaml>`) to handle -``HTTP``, ``HTTPS`` calls to the services and requests to ``/admin`` respectively. - -Moreover, notice that all traffic routed by the front Envoy to the service containers is actually -routed to the service Envoys (routes setup in :download:`envoy.yaml <_include/front-proxy/envoy.yaml>`). - -In turn the service Envoys route the request to the ``aiohttp`` app via the loopback -address (routes setup in :download:`service-envoy.yaml <_include/front-proxy/service-envoy.yaml>`). This -setup illustrates the advantage of running service Envoys collocated with your services: all -requests are handled by the service Envoy, and efficiently routed to your services. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/front-proxy`` directory. - -.. code-block:: console - - $ pwd - envoy/examples/front-proxy - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------------------------------------- - front-proxy_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8001->8001/tcp, 0.0.0.0:8443->8443/tcp - front-proxy_service1_1 python3 /code/service.py ... Up (healthy) - front-proxy_service2_1 python3 /code/service.py ... Up (healthy) - -Step 2: Test Envoy's routing capabilities -***************************************** - -You can now send a request to both services via the ``front-envoy``. - -For ``service1``: - -.. code-block:: console - - $ curl -v localhost:8080/service/1 - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /service/1 HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 92 - < server: envoy - < date: Mon, 06 Jul 2020 06:20:00 GMT - < x-envoy-upstream-service-time: 2 - < - Hello from behind Envoy (service 1)! hostname: 36418bc3c824 resolvedhostname: 192.168.160.4 - -For ``service2``: - -.. code-block:: console - - $ curl -v localhost:8080/service/2 - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /service/2 HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 92 - < server: envoy - < date: Mon, 06 Jul 2020 06:23:13 GMT - < x-envoy-upstream-service-time: 2 - < - Hello from behind Envoy (service 2)! hostname: ea6165ee4fee resolvedhostname: 192.168.160.2 - -Notice that each request, while sent to the front Envoy, was correctly routed to the respective -application. - -We can also use ``HTTPS`` to call services behind the front Envoy. For example, calling ``service1``: - -.. code-block:: console - - $ curl https://localhost:8443/service/1 -k -v - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8443 (#0) - * ALPN, offering h2 - * ALPN, offering http/1.1 - * successfully set certificate verify locations: - * CAfile: /etc/ssl/cert.pem - CApath: none - * TLSv1.2 (OUT), TLS handshake, Client hello (1): - * TLSv1.2 (IN), TLS handshake, Server hello (2): - * TLSv1.2 (IN), TLS handshake, Certificate (11): - * TLSv1.2 (IN), TLS handshake, Server key exchange (12): - * TLSv1.2 (IN), TLS handshake, Server finished (14): - * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): - * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): - * TLSv1.2 (OUT), TLS handshake, Finished (20): - * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): - * TLSv1.2 (IN), TLS handshake, Finished (20): - * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 - * ALPN, server did not agree to a protocol - * Server certificate: - * subject: CN=front-envoy - * start date: Jul 5 15:18:44 2020 GMT - * expire date: Jul 5 15:18:44 2021 GMT - * issuer: CN=front-envoy - * SSL certificate verify result: self signed certificate (18), continuing anyway. - > GET /service/1 HTTP/1.1 - > Host: localhost:8443 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 92 - < server: envoy - < date: Mon, 06 Jul 2020 06:17:14 GMT - < x-envoy-upstream-service-time: 3 - < - Hello from behind Envoy (service 1)! hostname: 36418bc3c824 resolvedhostname: 192.168.160.4 - -Step 3: Test Envoy's load balancing capabilities -************************************************ - -Now let's scale up our ``service1`` nodes to demonstrate the load balancing abilities of Envoy: - -.. code-block:: console - - $ docker compose scale service1=3 - Creating and starting example_service1_2 ... done - Creating and starting example_service1_3 ... done - -Now if we send a request to ``service1`` multiple times, the front Envoy will load balance the -requests by doing a round robin of the three ``service1`` machines: - -.. code-block:: console - - $ curl -v localhost:8080/service/1 - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /service/1 HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.64.1 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 92 - < server: envoy - < date: Mon, 06 Jul 2020 06:21:47 GMT - < x-envoy-upstream-service-time: 6 - < - Hello from behind Envoy (service 1)! hostname: 3dc787578c23 resolvedhostname: 192.168.160.6 - - $ curl -v localhost:8080/service/1 - * Trying 192.168.99.100... - * Connected to 192.168.99.100 (192.168.99.100) port 8080 (#0) - > GET /service/1 HTTP/1.1 - > Host: 192.168.99.100:8080 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 89 - < x-envoy-upstream-service-time: 1 - < server: envoy - < date: Fri, 26 Aug 2018 19:40:22 GMT - < - Hello from behind Envoy (service 1)! hostname: 3a93ece62129 resolvedhostname: 192.168.160.5 - - $ curl -v localhost:8080/service/1 - * Trying 192.168.99.100... - * Connected to 192.168.99.100 (192.168.99.100) port 8080 (#0) - > GET /service/1 HTTP/1.1 - > Host: 192.168.99.100:8080 - > User-Agent: curl/7.43.0 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 89 - < x-envoy-upstream-service-time: 1 - < server: envoy - < date: Fri, 26 Aug 2018 19:40:24 GMT - < x-envoy-protocol-version: HTTP/1.1 - < - Hello from behind Envoy (service 1)! hostname: 36418bc3c824 resolvedhostname: 192.168.160.4 - -Step 4: Enter containers and curl services -****************************************** - -In addition of using ``curl`` from your host machine, you can also enter the -containers themselves and ``curl`` from inside them. To enter a container you -can use ``docker compose exec /bin/bash``. For example we can -enter the ``front-envoy`` container, and ``curl`` for services locally: - -.. code-block:: console - - $ docker compose exec front-envoy /bin/bash - root@81288499f9d7:/# curl localhost:8080/service/1 - Hello from behind Envoy (service 1)! hostname: 85ac151715c6 resolvedhostname: 172.19.0.3 - root@81288499f9d7:/# curl localhost:8080/service/1 - Hello from behind Envoy (service 1)! hostname: 20da22cfc955 resolvedhostname: 172.19.0.5 - root@81288499f9d7:/# curl localhost:8080/service/1 - Hello from behind Envoy (service 1)! hostname: f26027f1ce28 resolvedhostname: 172.19.0.6 - root@81288499f9d7:/# curl localhost:8080/service/2 - Hello from behind Envoy (service 2)! hostname: 92f4a3737bbc resolvedhostname: 172.19.0.2 - -Step 5: Enter container and curl admin -************************************** - -When Envoy runs it also attaches an ``admin`` to your desired port. - -In the example configs the admin is bound to port ``8001``. - -We can ``curl`` it to gain useful information: - -- :ref:`/server_info ` provides information about the Envoy version you are running. -- :ref:`/stats ` provides statistics about the Envoy server. - -In the example we can enter the ``front-envoy`` container to query admin: - -.. code-block:: console - - $ docker compose exec front-envoy /bin/bash - root@e654c2c83277:/# curl localhost:8001/server_info - -.. code-block:: json - - { - "version": "093e2ffe046313242144d0431f1bb5cf18d82544/1.15.0-dev/Clean/RELEASE/BoringSSL", - "state": "LIVE", - "hot_restart_version": "11.104", - "command_line_options": { - "base_id": "0", - "use_dynamic_base_id": false, - "base_id_path": "", - "concurrency": 8, - "config_path": "/etc/envoy.yaml", - "config_yaml": "", - "allow_unknown_static_fields": false, - "reject_unknown_dynamic_fields": false, - "ignore_unknown_dynamic_fields": false, - "admin_address_path": "", - "local_address_ip_version": "v4", - "log_level": "info", - "component_log_level": "", - "log_format": "[%Y-%m-%d %T.%e][%t][%l][%n] [%g:%#] %v", - "log_format_escaped": false, - "log_path": "", - "service_cluster": "front-proxy", - "service_node": "", - "service_zone": "", - "drain_strategy": "Gradual", - "mode": "Serve", - "disable_hot_restart": false, - "enable_mutex_tracing": false, - "restart_epoch": 0, - "cpuset_threads": false, - "disabled_extensions": [], - "bootstrap_version": 0, - "hidden_envoy_deprecated_max_stats": "0", - "hidden_envoy_deprecated_max_obj_name_len": "0", - "file_flush_interval": "10s", - "drain_time": "600s", - "parent_shutdown_time": "900s" - }, - "uptime_current_epoch": "188s", - "uptime_all_epochs": "188s" - } - -.. code-block:: console - - root@e654c2c83277:/# curl localhost:8001/stats - cluster.service1.external.upstream_rq_200: 7 - ... - cluster.service1.membership_change: 2 - cluster.service1.membership_total: 3 - ... - cluster.service1.upstream_cx_http2_total: 3 - ... - cluster.service1.upstream_rq_total: 7 - ... - cluster.service2.external.upstream_rq_200: 2 - ... - cluster.service2.membership_change: 1 - cluster.service2.membership_total: 1 - ... - cluster.service2.upstream_cx_http2_total: 1 - ... - cluster.service2.upstream_rq_total: 2 - ... - -Notice that we can get the number of members of upstream clusters, number of requests fulfilled by -them, information about http ingress, and a plethora of other useful stats. - -.. seealso:: - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/front-proxy/service-envoy-2.yaml b/examples/front-proxy/service-envoy-2.yaml deleted file mode 100644 index 642b0cc468c1..000000000000 --- a/examples/front-proxy/service-envoy-2.yaml +++ /dev/null @@ -1,47 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: service_envoy_2 - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/2" - route: - cluster: service2 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2 - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/front-proxy/service-envoy.yaml b/examples/front-proxy/service-envoy.yaml deleted file mode 100644 index 14a61902856d..000000000000 --- a/examples/front-proxy/service-envoy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: service_envoy_1 - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/front-proxy/verify.sh b/examples/front-proxy/verify.sh deleted file mode 100755 index 398e85161a7e..000000000000 --- a/examples/front-proxy/verify.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -e - -export NAME=front-proxy -export PORT_PROXY="${FRONT_PROXY_PORT_PROXY:-10610}" -export PORT_HTTPS="${FRONT_PROXY_PORT_HTTPS:-10611}" -export PORT_STATS="${FRONT_PROXY_PORT_STATS:-10612}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test service: localhost:${PORT_PROXY}/service/1" -responds_with \ - "Hello from behind Envoy (service 1)!" \ - "http://localhost:${PORT_PROXY}/service/1" - -run_log "Test service: localhost:${PORT_PROXY}/service/2" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/service/2" - -run_log "Test service: https://localhost:${PORT_HTTPS}/service/1" -responds_with \ - "Hello from behind Envoy (service 1)!" \ - -k "https://localhost:${PORT_HTTPS}/service/1" - -run_log "Scale up docker service1=3" -"${DOCKER_COMPOSE[@]}" up --wait -d --scale service1=3 - -run_log "Test round-robin localhost:${PORT_PROXY}/service/1" -"${DOCKER_COMPOSE[@]}" exec -T front-envoy bash -c "\ - curl -s http://localhost:8080/service/1 \ - && curl -s http://localhost:8080/service/1 \ - && curl -s http://localhost:8080/service/1" \ - | grep Hello | grep "service 1" - -run_log "Test service inside front-envoy: localhost:${PORT_PROXY}/service/2" -"${DOCKER_COMPOSE[@]}" exec -T front-envoy curl -s "http://localhost:8080/service/2" | grep Hello | grep "service 2" - -run_log "Test service info: localhost:${PORT_STATS}/server_info" -"${DOCKER_COMPOSE[@]}" exec -T front-envoy curl -s "http://localhost:8001/server_info" | jq '.' - -run_log "Test service stats: localhost:${PORT_STATS}/stats" -"${DOCKER_COMPOSE[@]}" exec -T front-envoy curl -s "http://localhost:8001/stats" | grep ":" diff --git a/examples/go.mod b/examples/go.mod deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/examples/golang-http/README.md b/examples/golang-http/README.md deleted file mode 100644 index 73def7ce10f8..000000000000 --- a/examples/golang-http/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/golang.html). diff --git a/examples/golang-http/docker-compose-go.yaml b/examples/golang-http/docker-compose-go.yaml deleted file mode 100644 index 6d5d1e821486..000000000000 --- a/examples/golang-http/docker-compose-go.yaml +++ /dev/null @@ -1,17 +0,0 @@ -services: - go_plugin_compile: - build: - context: simple - dockerfile: ../../shared/golang/Dockerfile - target: golang-base - command: > - bash -c " - cd examples/golang-http/simple - && go build -o simple.so -buildmode=c-shared . - && cp ./simple.so /output" - working_dir: /source - environment: - - GOFLAGS=-buildvcs=false - volumes: - - ../..:/source - - ./lib:/output diff --git a/examples/golang-http/docker-compose.yaml b/examples/golang-http/docker-compose.yaml deleted file mode 100644 index 2b05743c1cd0..000000000000 --- a/examples/golang-http/docker-compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-go - args: - ENVOY_VARIANT: contrib-dev - depends_on: - helloworld_service: - condition: service_healthy - ports: - - "${PORT_PROXY:-10000}:10000" - - helloworld_service: - build: - context: ../shared/python - target: aiohttp-hello-service diff --git a/examples/golang-http/envoy.yaml b/examples/golang-http/envoy.yaml deleted file mode 100644 index e4a2c630fb66..000000000000 --- a/examples/golang-http/envoy.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# envoy demo with golang extension enabled -static_resources: - listeners: - - name: listener_0 - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.golang - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config - library_id: simple - library_path: "lib/simple.so" - plugin_name: simple - plugin_config: - "@type": type.googleapis.com/xds.type.v3.TypedStruct - value: - prefix_localreply_body: "Configured local reply from go" - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: ["*"] - routes: - - match: - prefix: "/" - route: - cluster: helloworld_service_cluster - clusters: - - name: helloworld_service_cluster - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: helloworld_service_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: helloworld_service - port_value: 8080 diff --git a/examples/golang-http/example.rst b/examples/golang-http/example.rst deleted file mode 100644 index 43680611d71b..000000000000 --- a/examples/golang-http/example.rst +++ /dev/null @@ -1,92 +0,0 @@ -.. _install_sandboxes_golang_http: - -Golang HTTP filter -================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we show how the `Golang `_ filter can be used with the Envoy -proxy. - -The example demonstrates a Go plugin that can respond directly to requests and also update responses provided by an upstream server. - -It also shows how Go plugins can be independently configured at runtime. - -Step 1: Compile the go plugin library -************************************* - -Change to the ``examples/golang-http`` directory and build the go plugin library. - -.. code-block:: console - - $ pwd - envoy/examples/golang-http - $ docker compose -f docker-compose-go.yaml run --rm go_plugin_compile - -The compiled library should now be in the ``lib`` folder. - -.. code-block:: console - - $ ls lib - simple.so - -Step 2: Start all of our containers -*********************************** - -Start all the containers. - -.. code-block:: console - - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------- - golang_proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp - golang_web_service_1 /bin/echo-server Up 8080/tcp - -Step 3: Make a request handled by the Go plugin -*********************************************** - -The output from the ``curl`` command below should include the header added by the simple Go plugin. - -.. code-block:: console - - $ curl -v localhost:10000 2>&1 | grep rsp-header-from-go - < rsp-header-from-go: bar-test - -Step 4: Make a request handled upstream and updated by the Go plugin -******************************************************************** - -The output from the ``curl`` command below should include the body that has been updated by the simple Go plugin. - -.. code-block:: console - - $ curl localhost:10000/update_upstream_response 2>&1 | grep "updated" - upstream response body updated by the simple plugin - -Step 5: Make a request handled by the Go plugin using custom configuration -************************************************************************** - -The output from the ``curl`` command below should include the body that contains value of -``prefix_localreply_body`` by the simple Go plugin. - -.. code-block:: console - - $ curl localhost:10000/localreply_by_config 2>&1 | grep "localreply" - Configured local reply from go, path: /localreply_by_config - -.. seealso:: - - :ref:`Envoy Go filter ` - Further information about the Envoy Go filter. - :ref:`Go extension API ` - The Go extension filter API. - :repo:`Go plugin API ` - Overview of Envoy's Go plugin APIs. diff --git a/examples/golang-http/simple/config.go b/examples/golang-http/simple/config.go deleted file mode 100644 index 2c635d9f02bb..000000000000 --- a/examples/golang-http/simple/config.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "errors" - "fmt" - - xds "github.com/cncf/xds/go/xds/type/v3" - "google.golang.org/protobuf/types/known/anypb" - - "github.com/envoyproxy/envoy/contrib/golang/common/go/api" - "github.com/envoyproxy/envoy/contrib/golang/filters/http/source/go/pkg/http" -) - -const Name = "simple" - -func init() { - http.RegisterHttpFilterFactoryAndConfigParser(Name, filterFactory, &parser{}) -} - -type config struct { - echoBody string - // other fields -} - -type parser struct { -} - -// Parse the filter configuration. We can call the ConfigCallbackHandler to control the filter's -// behavior -func (p *parser) Parse(any *anypb.Any, callbacks api.ConfigCallbackHandler) (interface{}, error) { - configStruct := &xds.TypedStruct{} - if err := any.UnmarshalTo(configStruct); err != nil { - return nil, err - } - - v := configStruct.Value - conf := &config{} - prefix, ok := v.AsMap()["prefix_localreply_body"] - if !ok { - return nil, errors.New("missing prefix_localreply_body") - } - if str, ok := prefix.(string); ok { - conf.echoBody = str - } else { - return nil, fmt.Errorf("prefix_localreply_body: expect string while got %T", prefix) - } - return conf, nil -} - -// Merge configuration from the inherited parent configuration -func (p *parser) Merge(parent interface{}, child interface{}) interface{} { - parentConfig := parent.(*config) - childConfig := child.(*config) - - // copy one, do not update parentConfig directly. - newConfig := *parentConfig - if childConfig.echoBody != "" { - newConfig.echoBody = childConfig.echoBody - } - return &newConfig -} - -func filterFactory(c interface{}, callbacks api.FilterCallbackHandler) api.StreamFilter { - conf, ok := c.(*config) - if !ok { - panic("unexpected config type") - } - return &filter{ - callbacks: callbacks, - config: conf, - } -} - -func main() {} diff --git a/examples/golang-http/simple/filter.go b/examples/golang-http/simple/filter.go deleted file mode 100644 index b5bc5542669f..000000000000 --- a/examples/golang-http/simple/filter.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "fmt" - "strconv" - - "github.com/envoyproxy/envoy/contrib/golang/common/go/api" -) - -var UpdateUpstreamBody = "upstream response body updated by the simple plugin" - -// The callbacks in the filter, like `DecodeHeaders`, can be implemented on demand. -// Because api.PassThroughStreamFilter provides a default implementation. -type filter struct { - api.PassThroughStreamFilter - - callbacks api.FilterCallbackHandler - path string - config *config -} - -func (f *filter) sendLocalReplyInternal() api.StatusType { - body := fmt.Sprintf("%s, path: %s\r\n", f.config.echoBody, f.path) - f.callbacks.DecoderFilterCallbacks().SendLocalReply(200, body, nil, 0, "") - // Remember to return LocalReply when the request is replied locally - return api.LocalReply -} - -// Callbacks which are called in request path -// The endStream is true if the request doesn't have body -func (f *filter) DecodeHeaders(header api.RequestHeaderMap, endStream bool) api.StatusType { - f.path, _ = header.Get(":path") - api.LogDebugf("get path %s", f.path) - - if f.path == "/localreply_by_config" { - return f.sendLocalReplyInternal() - } - return api.Continue - /* - // If the code is time-consuming, to avoid blocking the Envoy, - // we need to run the code in a background goroutine - // and suspend & resume the filter - go func() { - defer f.callbacks.DecoderFilterCallbacks().RecoverPanic() - // do time-consuming jobs - - // resume the filter - f.callbacks.DecoderFilterCallbacks().Continue(status) - }() - - // suspend the filter - return api.Running - */ -} - -// DecodeData might be called multiple times during handling the request body. -// The endStream is true when handling the last piece of the body. -func (f *filter) DecodeData(buffer api.BufferInstance, endStream bool) api.StatusType { - // support suspending & resuming the filter in a background goroutine - return api.Continue -} - -func (f *filter) DecodeTrailers(trailers api.RequestTrailerMap) api.StatusType { - // support suspending & resuming the filter in a background goroutine - return api.Continue -} - -// Callbacks which are called in response path -// The endStream is true if the response doesn't have body -func (f *filter) EncodeHeaders(header api.ResponseHeaderMap, endStream bool) api.StatusType { - if f.path == "/update_upstream_response" { - header.Set("Content-Length", strconv.Itoa(len(UpdateUpstreamBody))) - } - header.Set("Rsp-Header-From-Go", "bar-test") - // support suspending & resuming the filter in a background goroutine - return api.Continue -} - -// EncodeData might be called multiple times during handling the response body. -// The endStream is true when handling the last piece of the body. -func (f *filter) EncodeData(buffer api.BufferInstance, endStream bool) api.StatusType { - if f.path == "/update_upstream_response" { - if endStream { - buffer.SetString(UpdateUpstreamBody) - } else { - buffer.Reset() - } - } - // support suspending & resuming the filter in a background goroutine - return api.Continue -} - -func (f *filter) EncodeTrailers(trailers api.ResponseTrailerMap) api.StatusType { - return api.Continue -} - -// OnLog is called when the HTTP stream is ended on HTTP Connection Manager filter. -func (f *filter) OnLog() { - code, _ := f.callbacks.StreamInfo().ResponseCode() - respCode := strconv.Itoa(int(code)) - api.LogDebug(respCode) - - /* - // It's possible to kick off a goroutine here. - // But it's unsafe to access the f.callbacks because the FilterCallbackHandler - // may be already released when the goroutine is scheduled. - go func() { - defer func() { - if p := recover(); p != nil { - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:runtime.Stack(buf, false)] - fmt.Printf("http: panic serving: %v\n%s", p, buf) - } - }() - - // do time-consuming jobs - }() - */ -} - -// OnLogDownstreamStart is called when HTTP Connection Manager filter receives a new HTTP request -// (required the corresponding access log type is enabled) -func (f *filter) OnLogDownstreamStart() { - // also support kicking off a goroutine here, like OnLog. -} - -// OnLogDownstreamPeriodic is called on any HTTP Connection Manager periodic log record -// (required the corresponding access log type is enabled) -func (f *filter) OnLogDownstreamPeriodic() { - // also support kicking off a goroutine here, like OnLog. -} - -func (f *filter) OnDestroy(reason api.DestroyReason) { - // One should not access f.callbacks here because the FilterCallbackHandler - // is released. But we can still access other Go fields in the filter f. - - // goroutine can be used everywhere. -} diff --git a/examples/golang-http/simple/go.mod b/examples/golang-http/simple/go.mod deleted file mode 100644 index ac19b6ad7afd..000000000000 --- a/examples/golang-http/simple/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module github.com/envoyproxy/envoy/examples/golang-http/simple - -// the version should >= 1.18 -go 1.20 - -// NOTICE: these lines could be generated automatically by "go mod tidy" -require ( - github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa - github.com/envoyproxy/envoy v1.24.0 - google.golang.org/protobuf v1.34.2 -) - -require ( - github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect -) - -// TODO: remove when #26173 lands. -// And check the "API compatibility" section in doc: -// https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/golang_filter#developing-a-go-plugin -replace github.com/envoyproxy/envoy => ../../.. diff --git a/examples/golang-http/simple/go.sum b/examples/golang-http/simple/go.sum deleted file mode 100644 index 93cdbfb59e6c..000000000000 --- a/examples/golang-http/simple/go.sum +++ /dev/null @@ -1,18 +0,0 @@ -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= diff --git a/examples/golang-http/verify.sh b/examples/golang-http/verify.sh deleted file mode 100755 index 163efc9fb39c..000000000000 --- a/examples/golang-http/verify.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -export NAME=golang -export UID -export MANUAL=true -export PORT_PROXY="${GOLANG_PORT_PROXY:-10710}" - - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Compile the go plugin library" -"${DOCKER_COMPOSE[@]}" -f docker-compose-go.yaml up --quiet-pull --remove-orphans go_plugin_compile - -run_log "Start all of our containers" -bring_up_example - -wait_for 10 bash -c "responds_with_header 'rsp-header-from-go: bar-test' http://localhost:${PORT_PROXY}" - -run_log "Make a request handled by the Go plugin" -responds_with_header \ - "rsp-header-from-go: bar-test" \ - "http://localhost:${PORT_PROXY}" - -run_log "Make a request handled upstream and updated by the Go plugin" -responds_with \ - "upstream response body updated by the simple plugin" \ - "http://localhost:${PORT_PROXY}/update_upstream_response" - -run_log "Make a request handled by the Go plugin using custom configuration" -responds_with \ - "Configured local reply from go, path: /localreply_by_config" \ - "http://localhost:${PORT_PROXY}/localreply_by_config" diff --git a/examples/golang-network/Dockerfile-echo b/examples/golang-network/Dockerfile-echo deleted file mode 100644 index 52c5b0ff12da..000000000000 --- a/examples/golang-network/Dockerfile-echo +++ /dev/null @@ -1 +0,0 @@ -FROM cjimti/go-echo@sha256:ff9ac5cb2051d7ec0ba7b12b805550bbcb87966e9d5c288d75c18f87d9d861e9 diff --git a/examples/golang-network/README.md b/examples/golang-network/README.md deleted file mode 100644 index ef68f96dce2b..000000000000 --- a/examples/golang-network/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/golang-network.html). diff --git a/examples/golang-network/docker-compose-go.yaml b/examples/golang-network/docker-compose-go.yaml deleted file mode 100644 index eeb68aa6dad4..000000000000 --- a/examples/golang-network/docker-compose-go.yaml +++ /dev/null @@ -1,17 +0,0 @@ -services: - go_plugin_compile: - build: - context: simple - dockerfile: ../../shared/golang/Dockerfile - target: golang-base - command: > - bash -c " - cd examples/golang-network/simple - && go build -o simple.so -buildmode=c-shared . - && cp ./simple.so /output" - working_dir: /source - environment: - - GOFLAGS=-buildvcs=false - volumes: - - ../..:/source - - ./lib:/output diff --git a/examples/golang-network/docker-compose.yaml b/examples/golang-network/docker-compose.yaml deleted file mode 100644 index 0835a7f8b01b..000000000000 --- a/examples/golang-network/docker-compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-go - args: - ENVOY_VARIANT: contrib-dev - depends_on: - - echo_service - ports: - - "${PORT_PROXY:-10000}:10000" - - echo_service: - build: - context: . - dockerfile: Dockerfile-echo - hostname: echo_service diff --git a/examples/golang-network/envoy.yaml b/examples/golang-network/envoy.yaml deleted file mode 100644 index 4a96a9091f31..000000000000 --- a/examples/golang-network/envoy.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# envoy demo with golang extension enabled -static_resources: - listeners: - - name: listener_0 - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.golang - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.golang.v3alpha.Config - is_terminal_filter: true - library_id: simple - library_path: "/lib/simple.so" - plugin_name: simple - plugin_config: - "@type": type.googleapis.com/xds.type.v3.TypedStruct - value: - echo_server_addr: echo_service - clusters: - - name: plainText - type: ORIGINAL_DST - lb_policy: CLUSTER_PROVIDED diff --git a/examples/golang-network/example.rst b/examples/golang-network/example.rst deleted file mode 100644 index 1b5403ab1b20..000000000000 --- a/examples/golang-network/example.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. _install_sandboxes_golang_network: - -Golang network filter -===================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`netcat ` - Used to send TCP data. - -In this example, we show how the `Golang `_ network filter can be used with the Envoy proxy. We also show how the Go plugins can be independently configured at runtime. - -The example Go plugin adds a :literal:`hello, \ ` prefix to the requests received from its TCP connections. These modified requests are then proxied to an echo service that is retrieved from the configuration file. - -.. code-block:: yaml - :emphasize-lines: 4 - - plugin_config: - "@type": type.googleapis.com/xds.type.v3.TypedStruct - value: - echo_server_addr: echo_service - - -Step 1: Compile the go plugin library -************************************* - -Change to the ``examples/golang-network`` directory and build the go plugin library. - -.. code-block:: console - - $ pwd - envoy/examples/golang-network - $ docker compose -f docker-compose-go.yaml run --rm go_plugin_compile - -The compiled library should now be in the ``lib`` folder. - -.. code-block:: console - - $ ls lib - simple.so - -Step 2: Start all of our containers -*********************************** - -Start all the containers. - -.. code-block:: console - - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - NAME COMMAND SERVICE STATUS PORTS - golang-network-echo_service-1 "/tcp-echo" echo_service running - golang-network-proxy-1 "/docker-entrypoint.…" proxy running 0.0.0.0:10000->10000/tcp - -In this example, we start up two containers - an echo service which simply responds to what it has received from its TCP connections, and a proxy service that utilizes a Golang plugin to process and proxy data to the echo service. - -Step 3: Send some data to be handled by the Go plugin -***************************************************** - -The response from the ``nc`` command below should include the :literal:`hello, \ ` prefix which will be added by the example Go plugin. - -.. code-block:: console - - $ echo "world" | nc localhost 10000 2>&1 - < hello, world - -.. seealso:: - - :ref:`Envoy Go network filter ` - Further information about the Envoy Go network filter. - :ref:`Envoy Go HTTP filter ` - Further information about the Envoy Go HTTP filter. - :repo:`Go plugin API ` - Overview of Envoy's Go plugin APIs. diff --git a/examples/golang-network/simple/BUILD b/examples/golang-network/simple/BUILD deleted file mode 100644 index ac7b55fe0f5a..000000000000 --- a/examples/golang-network/simple/BUILD +++ /dev/null @@ -1,21 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_binary") - -licenses(["notice"]) # Apache 2 - -go_binary( - name = "simple.so", - srcs = [ - "filter.go", - ], - out = "simple.so", - cgo = True, - importpath = "github.com/envoyproxy/envoy/examples/golang-network/simple", - linkmode = "c-shared", - visibility = ["//visibility:public"], - deps = [ - "//contrib/golang/common/go/api", - "//contrib/golang/filters/network/source/go/pkg/network", - "@com_github_cncf_xds_go//xds/type/v3:type", - "@org_golang_google_protobuf//types/known/anypb", - ], -) diff --git a/examples/golang-network/simple/filter.go b/examples/golang-network/simple/filter.go deleted file mode 100644 index 615d3a0e6aae..000000000000 --- a/examples/golang-network/simple/filter.go +++ /dev/null @@ -1,132 +0,0 @@ -package main - -import ( - "fmt" - "net" - - xds "github.com/cncf/xds/go/xds/type/v3" - "google.golang.org/protobuf/types/known/anypb" - - "github.com/envoyproxy/envoy/contrib/golang/common/go/api" - "github.com/envoyproxy/envoy/contrib/golang/filters/network/source/go/pkg/network" -) - -func init() { - network.RegisterNetworkFilterConfigFactory("simple", cf) -} - -var cf = &configFactory{} - -type configFactory struct{} - -func (f *configFactory) CreateFactoryFromConfig(config interface{}) network.FilterFactory { - a := config.(*anypb.Any) - configStruct := &xds.TypedStruct{} - _ = a.UnmarshalTo(configStruct) - - v := configStruct.Value.AsMap()["echo_server_addr"] - addr, err := net.LookupHost(v.(string)) - if err != nil { - fmt.Printf("fail to resolve: %v, err: %v\n", v.(string), err) - return nil - } - upAddr := addr[0] + ":1025" - - return &filterFactory{ - upAddr: upAddr, - } -} - -type filterFactory struct { - upAddr string -} - -func (f *filterFactory) CreateFilter(cb api.ConnectionCallback) api.DownstreamFilter { - return &downFilter{ - upAddr: f.upAddr, - cb: cb, - } -} - -type downFilter struct { - api.EmptyDownstreamFilter - - cb api.ConnectionCallback - upAddr string - upFilter *upFilter -} - -func (f *downFilter) OnNewConnection() api.FilterStatus { - localAddr, _ := f.cb.StreamInfo().UpstreamLocalAddress() - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnNewConnection, local: %v, remote: %v, connect to: %v\n", localAddr, remoteAddr, f.upAddr) - f.upFilter = &upFilter{ - downFilter: f, - ch: make(chan []byte, 1), - } - network.CreateUpstreamConn(f.upAddr, f.upFilter) - return api.NetworkFilterContinue -} - -func (f *downFilter) OnData(buffer []byte, endOfStream bool) api.FilterStatus { - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnData, addr: %v, buffer: %v, endOfStream: %v\n", remoteAddr, string(buffer), endOfStream) - buffer = append([]byte("hello, "), buffer...) - f.upFilter.ch <- buffer - return api.NetworkFilterContinue -} - -func (f *downFilter) OnEvent(event api.ConnectionEvent) { - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnEvent, addr: %v, event: %v\n", remoteAddr, event) -} - -func (f *downFilter) OnWrite(buffer []byte, endOfStream bool) api.FilterStatus { - fmt.Printf("OnWrite, buffer: %v, endOfStream: %v\n", string(buffer), endOfStream) - return api.NetworkFilterContinue -} - -type upFilter struct { - api.EmptyUpstreamFilter - - cb api.ConnectionCallback - downFilter *downFilter - ch chan []byte -} - -func (f *upFilter) OnPoolReady(cb api.ConnectionCallback) { - f.cb = cb - f.cb.EnableHalfClose(false) - localAddr, _ := f.cb.StreamInfo().UpstreamLocalAddress() - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnPoolReady, local: %v, remote: %v\n", localAddr, remoteAddr) - go func() { - for { - buf, ok := <-f.ch - if !ok { - return - } - f.cb.Write(buf, false) - } - }() -} - -func (f *upFilter) OnPoolFailure(poolFailureReason api.PoolFailureReason, transportFailureReason string) { - fmt.Printf("OnPoolFailure, reason: %v, transportFailureReason: %v\n", poolFailureReason, transportFailureReason) -} - -func (f *upFilter) OnData(buffer []byte, endOfStream bool) { - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnData, addr: %v, buffer: %v, endOfStream: %v\n", remoteAddr, string(buffer), endOfStream) - f.downFilter.cb.Write(buffer, endOfStream) -} - -func (f *upFilter) OnEvent(event api.ConnectionEvent) { - remoteAddr, _ := f.cb.StreamInfo().UpstreamRemoteAddress() - fmt.Printf("OnEvent, addr: %v, event: %v\n", remoteAddr, event) - if event == api.LocalClose || event == api.RemoteClose { - close(f.ch) - } -} - -func main() {} diff --git a/examples/golang-network/simple/go.mod b/examples/golang-network/simple/go.mod deleted file mode 100644 index 385db640eeaa..000000000000 --- a/examples/golang-network/simple/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module github.com/envoyproxy/envoy/examples/golang-network/simple - -// the version should >= 1.18 -go 1.18 - -// NOTICE: these lines could be generated automatically by "go mod tidy" -require ( - github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa - github.com/envoyproxy/envoy v1.24.0 - google.golang.org/protobuf v1.34.2 -) - -require ( - github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect -) - -// TODO: remove when #26173 lands. -replace github.com/envoyproxy/envoy => ../../.. diff --git a/examples/golang-network/simple/go.sum b/examples/golang-network/simple/go.sum deleted file mode 100644 index 93cdbfb59e6c..000000000000 --- a/examples/golang-network/simple/go.sum +++ /dev/null @@ -1,18 +0,0 @@ -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= diff --git a/examples/golang-network/verify.sh b/examples/golang-network/verify.sh deleted file mode 100755 index 276d6a7b16e6..000000000000 --- a/examples/golang-network/verify.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -export NAME=golang-network -export UID -export MANUAL=true -export PORT_PROXY="${GOLANG_NETWORK_PORT_PROXY:-10720}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Compile the go plugin library" -"${DOCKER_COMPOSE[@]}" -f docker-compose-go.yaml up --quiet-pull --remove-orphans go_plugin_compile - -run_log "Start all of our containers" -bring_up_example - -run_log "Send tcp data handled by the Go plugin" -echo -n "world" | nc -w1 127.0.0.1 "${PORT_PROXY}" - -run_log "Check echo server log" -"${DOCKER_COMPOSE[@]}" logs echo_service | grep "hello, world" diff --git a/examples/grpc-bridge/.gitignore b/examples/grpc-bridge/.gitignore deleted file mode 100644 index 0e57261fc9a9..000000000000 --- a/examples/grpc-bridge/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.idea -server/kv/kv.pb.go -client/kv/kv_pb2.py diff --git a/examples/grpc-bridge/Dockerfile-grpc-go b/examples/grpc-bridge/Dockerfile-grpc-go deleted file mode 100644 index 8b74dbaddba4..000000000000 --- a/examples/grpc-bridge/Dockerfile-grpc-go +++ /dev/null @@ -1 +0,0 @@ -FROM grpc/go@sha256:0d3bb1fbfab306680ebaf751992bd2db2a0322106e4b389e85028a027242c2bc diff --git a/examples/grpc-bridge/Dockerfile-grpc-python b/examples/grpc-bridge/Dockerfile-grpc-python deleted file mode 100644 index 800c00915b81..000000000000 --- a/examples/grpc-bridge/Dockerfile-grpc-python +++ /dev/null @@ -1 +0,0 @@ -FROM grpc/python@sha256:6f0898ac290991eab0c262fa18453904f75286f17978d3185164d01400dc042e diff --git a/examples/grpc-bridge/README.md b/examples/grpc-bridge/README.md deleted file mode 100644 index e3d746fa0264..000000000000 --- a/examples/grpc-bridge/README.md +++ /dev/null @@ -1,131 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/grpc_bridge) - -# gRPC HTTP/1.1 to HTTP/2 bridge - -This is an example of a key-value store where a client CLI, written in Python, updates a remote store, written in Go, using the stubs generated for both languages. - -Running clients that uses gRPC stubs and sends messages through a proxy -that upgrades the HTTP requests from http/1.1 to http/2. This is a more detailed -implementation of the Envoy documentation at https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/grpc_bridge - -* Client: talks in python and sends HTTP/1.1 requests (gRPC stubs) - * Client-Proxy: Envoy setup that acts as an egress and converts the HTTP/1.1 call to HTTP/2. -* Server: talks in golang and receives HTTP/2 requests (gRPC stubs) - * Server-Proxy: Envoy setup that acts as an ingress and receives the HTTP/2 calls - -`[client](http/1.1) -> [client-egress-proxy](http/2) -> [server-ingress-proxy](http/2) -> [server]` - -# Running in 3 Steps - -* Generate Stubs: both the `client` and `server` stubs in `python` and `go` respectively to be used by each server. -* Start Both Client and Server Servers and Proxies: ` -* Use the Client CLI to make calls to the kv server. - -## Generate Stubs - -* Uses the `protos` dir and generates the stubs for both `client` and `server` -* Inspect the file `docker-compose-protos.yaml` with the gRPC protoc commands to generate the stubs. - -```console -$ docker-compose -f docker-compose-protos.yaml up --remove-orphans -Starting grpc-bridge_stubs_python_1 ... done -Starting grpc-bridge_stubs_go_1 ... done -Attaching to grpc-bridge_stubs_go_1, grpc-bridge_stubs_python_1 -grpc-bridge_stubs_go_1 exited with code 0 -grpc-bridge_stubs_python_1 exited with code 0 -``` - -* The files created were the `kv` modules for both the client and server respective dir. - * Note that both stubs are their respective languages. - * For each language, use its ways to include the stubs as an external module. - -```console -$ ls -la client/kv/kv_pb2.py --rw-r--r-- 1 mdesales CORP\Domain Users 9527 Nov 6 21:59 client/kv/kv_pb2.py - -$ ls -la server/kv/kv.pb.go --rw-r--r-- 1 mdesales CORP\Domain Users 9994 Nov 6 21:59 server/kv/kv.pb.go -``` - -## Start Both Client and Server and Proxies - -* After the stubs are in place, start the containers described in `docker-compose.yaml`. - -```console -$ docker-compose up --build -``` - -* Inspect the files `client/envoy-proxy.yaml` and `server/envoy-proxy.yaml`, as they define configs for their respective container, comparing port numbers and other specific settings. - -Notice that you will be interacting with the client container, which hosts -the client python CLI. The port numbers for the proxies and the containers are displayed -by the `docker-compose ps`, so it's easier to compare with the `\*/envoy-proxy.yaml` config files for each -of the containers how they match. - -Note that the client container to use is `grpc-bridge_grpc-client_1` and binds to no port -as it will use the `python` CLI. - -```console -$ docker-compose ps - Name Command State Ports ------------------------------------------------------------------------------------------------------------------------------------- -grpc-bridge_grpc-client-proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:9911->9911/tcp, 0.0.0.0:9991->9991/tcp -grpc-bridge_grpc-client_1 /bin/sh -c tail -f /dev/null Up -grpc-bridge_grpc-server-proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:8811->8811/tcp, 0.0.0.0:8881->8881/tcp -grpc-bridge_grpc-server_1 /bin/sh -c /bin/server Up 0.0.0.0:8081->8081/tcp -``` - -## Use the Client CLI - -* Since the containers are running, you can use the client container to interact with the gRPC server through the proxies -* The client has the methods `set key value` and `get key` to use the in-memory key-value store. - -```console -$ docker-compose exec grpc-client /client/grpc-kv-client.py set foo bar -setf foo to bar -``` - -> NOTE: You could also run docker instead of docker-compose `docker exec -ti grpc-bridge_grpc-client_1 /client/grpc-kv-client.py set foo bar` - -* The server will display the gRPC call received by the server, and then the access logs from the proxy for the SET method. - * Note that the proxy is propagating the headers of the request - -```console -grpc-server_1 | 2019/11/07 16:33:58 set: foo = bar -grpc-server-proxy_1 | [2019-11-07T16:33:58.856Z] "POST /kv.KV/Set HTTP/1.1" 200 - 15 7 3 1 "172.24.0.3" "python-requests/2.22.0" "c11cf735-0647-4e67-965c-5b1e362a5532" "grpc" "172.24.0.2:8081" -grpc-client-proxy_1 | [2019-11-07T16:33:58.855Z] "POST /kv.KV/Set HTTP/1.1" 200 - 15 7 5 3 "172.24.0.3" "python-requests/2.22.0" "c11cf735-0647-4e67-965c-5b1e362a5532" "grpc" "172.24.0.5:8811" -``` - -* Getting the value is no different - -```console -$ docker-compose exec grpc-client /client/grpc-kv-client.py get foo -bar -``` - -> NOTE: You could also run docker instead of docker-compose `docker exec -ti grpc-bridge_grpc-client_1 /client/grpc-kv-client.py get foo` - -* The logs in the server will show the same for the GET method. - * Note that again the request ID is proxied through - -```console -grpc-server_1 | 2019/11/07 16:34:50 get: foo -grpc-server-proxy_1 | [2019-11-07T16:34:50.456Z] "POST /kv.KV/Get HTTP/1.1" 200 - 10 10 2 1 "172.24.0.3" "python-requests/2.22.0" "727d4dcd-a276-4bb2-b4cc-494ae7119c24" "grpc" "172.24.0.2:8081" -grpc-client-proxy_1 | [2019-11-07T16:34:50.455Z] "POST /kv.KV/Get HTTP/1.1" 200 - 10 10 3 2 "172.24.0.3" "python-requests/2.22.0" "727d4dcd-a276-4bb2-b4cc-494ae7119c24" "grpc" "172.24.0.5:8811" -``` - -# Troubleshooting - -* Errors building the `client` or `server` are related to the missing gRPC stubs. -* Make sure to produce the stubs before building - * The error below is when the server is missing the stubs in the kv dir. - -```console -$ go build -o server -go: finding github.com/envoyproxy/envoy/examples/grpc-bridge latest -go: finding github.com/envoyproxy/envoy/examples latest -go: finding github.com/envoyproxy/envoy/examples/grpc-bridge/server/kv latest -go: finding github.com/envoyproxy/envoy/examples/grpc-bridge/server latest -build github.com/envoyproxy/envoy: cannot load github.com/envoyproxy/envoy/examples/grpc-bridge/server/kv: no matching versions for query "latest" -``` diff --git a/examples/grpc-bridge/client/client.py b/examples/grpc-bridge/client/client.py deleted file mode 100755 index e98607cbcfca..000000000000 --- a/examples/grpc-bridge/client/client.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python - -import requests, sys -import os - -# Stubs generated by protoc -from kv import kv_pb2 as kv - -from struct import pack - -HOST = os.getenv('CLIENT_PROXY', "http://localhost:9001") -HEADERS = {'content-type': 'application/grpc', 'Host': 'grpc'} -USAGE = """ -grpc-client usage [{host}]: - ./client.py set - sets the and - ./client.py get - gets the value for - - Set env var CLIENT_PROXY to change to a different host - """.format(host=HOST) - - -class KVClient: - - def get(self, key): - r = kv.GetRequest(key=key) - - # Build the gRPC frame - data = r.SerializeToString() - data = pack('!cI', b'\0', len(data)) + data - - resp = requests.post(HOST + "/kv.KV/Get", data=data, headers=HEADERS) - - return kv.GetResponse().FromString(resp.content[5:]) - - def set(self, key, value): - r = kv.SetRequest(key=key, value=value) - data = r.SerializeToString() - data = pack('!cI', b'\0', len(data)) + data - - return requests.post(HOST + "/kv.KV/Set", data=data, headers=HEADERS) - - -def main(): - if len(sys.argv) == 1: - print(USAGE) - - sys.exit(0) - - cmd = sys.argv[1] - - client = KVClient() - - if cmd == "get": - # ensure a key was provided - if len(sys.argv) != 3: - print(USAGE) - sys.exit(1) - - # get the key to fetch - key = sys.argv[2] - - # send the request to the server - response = client.get(key) - - print(response.value) - sys.exit(0) - - elif cmd == "set": - # ensure a key and value were provided - if len(sys.argv) < 4: - print(USAGE) - sys.exit(1) - - # get the key and the full text of value - key = sys.argv[2] - value = " ".join(sys.argv[3:]) - - # send the request to the server - response = client.set(key, value) - - print("setf %s to %s" % (key, value)) - - -if __name__ == '__main__': - main() diff --git a/examples/grpc-bridge/client/envoy-proxy.yaml b/examples/grpc-bridge/client/envoy-proxy.yaml deleted file mode 100644 index ff017b671c76..000000000000 --- a/examples/grpc-bridge/client/envoy-proxy.yaml +++ /dev/null @@ -1,58 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 9911 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - add_user_agent: true - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - stat_prefix: egress_http - common_http_protocol_options: - idle_timeout: 0.840s - use_remote_address: true - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - grpc - routes: - - match: - prefix: "/" - route: - cluster: backend-proxy - http_filters: - - name: envoy.filters.http.grpc_http1_bridge - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_http1_bridge.v3.Config - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: backend-proxy - type: LOGICAL_DNS - dns_lookup_family: V4_ONLY - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http_protocol_options: {} - load_assignment: - cluster_name: backend-proxy - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: grpc-server-proxy - port_value: 8811 diff --git a/examples/grpc-bridge/client/kv/__init__.py b/examples/grpc-bridge/client/kv/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/examples/grpc-bridge/client/requirements.in b/examples/grpc-bridge/client/requirements.in deleted file mode 100644 index 96b06d428c7e..000000000000 --- a/examples/grpc-bridge/client/requirements.in +++ /dev/null @@ -1,4 +0,0 @@ -requests>=2.22.0 -grpcio -grpcio-tools -protobuf>=3.18.0 diff --git a/examples/grpc-bridge/client/requirements.txt b/examples/grpc-bridge/client/requirements.txt deleted file mode 100644 index 620edcc4e603..000000000000 --- a/examples/grpc-bridge/client/requirements.txt +++ /dev/null @@ -1,233 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -certifi==2024.7.4 \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 - # via requests -charset-normalizer==3.3.0 \ - --hash=sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843 \ - --hash=sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786 \ - --hash=sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e \ - --hash=sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8 \ - --hash=sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4 \ - --hash=sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa \ - --hash=sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d \ - --hash=sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82 \ - --hash=sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7 \ - --hash=sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895 \ - --hash=sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d \ - --hash=sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a \ - --hash=sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382 \ - --hash=sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678 \ - --hash=sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b \ - --hash=sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e \ - --hash=sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741 \ - --hash=sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4 \ - --hash=sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596 \ - --hash=sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9 \ - --hash=sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69 \ - --hash=sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c \ - --hash=sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77 \ - --hash=sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13 \ - --hash=sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459 \ - --hash=sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e \ - --hash=sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7 \ - --hash=sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908 \ - --hash=sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a \ - --hash=sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f \ - --hash=sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8 \ - --hash=sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482 \ - --hash=sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d \ - --hash=sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d \ - --hash=sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545 \ - --hash=sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34 \ - --hash=sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86 \ - --hash=sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6 \ - --hash=sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe \ - --hash=sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e \ - --hash=sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc \ - --hash=sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7 \ - --hash=sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd \ - --hash=sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c \ - --hash=sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557 \ - --hash=sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a \ - --hash=sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89 \ - --hash=sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078 \ - --hash=sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e \ - --hash=sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4 \ - --hash=sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403 \ - --hash=sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0 \ - --hash=sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89 \ - --hash=sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115 \ - --hash=sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9 \ - --hash=sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05 \ - --hash=sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a \ - --hash=sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec \ - --hash=sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56 \ - --hash=sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38 \ - --hash=sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479 \ - --hash=sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c \ - --hash=sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e \ - --hash=sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd \ - --hash=sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186 \ - --hash=sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455 \ - --hash=sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c \ - --hash=sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65 \ - --hash=sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78 \ - --hash=sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287 \ - --hash=sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df \ - --hash=sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43 \ - --hash=sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1 \ - --hash=sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7 \ - --hash=sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989 \ - --hash=sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a \ - --hash=sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63 \ - --hash=sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884 \ - --hash=sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649 \ - --hash=sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810 \ - --hash=sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828 \ - --hash=sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4 \ - --hash=sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2 \ - --hash=sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd \ - --hash=sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5 \ - --hash=sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe \ - --hash=sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293 \ - --hash=sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e \ - --hash=sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e \ - --hash=sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8 - # via requests -grpcio==1.65.1 \ - --hash=sha256:12e9bdf3b5fd48e5fbe5b3da382ad8f97c08b47969f3cca81dd9b36b86ed39e2 \ - --hash=sha256:1bceeec568372cbebf554eae1b436b06c2ff24cfaf04afade729fb9035408c6c \ - --hash=sha256:1faaf7355ceed07ceaef0b9dcefa4c98daf1dd8840ed75c2de128c3f4a4d859d \ - --hash=sha256:1fbd6331f18c3acd7e09d17fd840c096f56eaf0ef830fbd50af45ae9dc8dfd83 \ - --hash=sha256:27adee2338d697e71143ed147fe286c05810965d5d30ec14dd09c22479bfe48a \ - --hash=sha256:2ca684ba331fb249d8a1ce88db5394e70dbcd96e58d8c4b7e0d7b141a453dce9 \ - --hash=sha256:2f56b5a68fdcf17a0a1d524bf177218c3c69b3947cb239ea222c6f1867c3ab68 \ - --hash=sha256:3019fb50128b21a5e018d89569ffaaaa361680e1346c2f261bb84a91082eb3d3 \ - --hash=sha256:34966cf526ef0ea616e008d40d989463e3db157abb213b2f20c6ce0ae7928875 \ - --hash=sha256:3c492301988cd720cd145d84e17318d45af342e29ef93141228f9cd73222368b \ - --hash=sha256:3dc5f928815b8972fb83b78d8db5039559f39e004ec93ebac316403fe031a062 \ - --hash=sha256:4effc0562b6c65d4add6a873ca132e46ba5e5a46f07c93502c37a9ae7f043857 \ - --hash=sha256:54cb822e177374b318b233e54b6856c692c24cdbd5a3ba5335f18a47396bac8f \ - --hash=sha256:557de35bdfbe8bafea0a003dbd0f4da6d89223ac6c4c7549d78e20f92ead95d9 \ - --hash=sha256:5f096ffb881f37e8d4f958b63c74bfc400c7cebd7a944b027357cd2fb8d91a57 \ - --hash=sha256:5fd7337a823b890215f07d429f4f193d24b80d62a5485cf88ee06648591a0c57 \ - --hash=sha256:60f1f38eed830488ad2a1b11579ef0f345ff16fffdad1d24d9fbc97ba31804ff \ - --hash=sha256:6e71aed8835f8d9fbcb84babc93a9da95955d1685021cceb7089f4f1e717d719 \ - --hash=sha256:71a05fd814700dd9cb7d9a507f2f6a1ef85866733ccaf557eedacec32d65e4c2 \ - --hash=sha256:76e81a86424d6ca1ce7c16b15bdd6a964a42b40544bf796a48da241fdaf61153 \ - --hash=sha256:7ae15275ed98ea267f64ee9ddedf8ecd5306a5b5bb87972a48bfe24af24153e8 \ - --hash=sha256:7af64838b6e615fff0ec711960ed9b6ee83086edfa8c32670eafb736f169d719 \ - --hash=sha256:8333ca46053c35484c9f2f7e8d8ec98c1383a8675a449163cea31a2076d93de8 \ - --hash=sha256:8558f0083ddaf5de64a59c790bffd7568e353914c0c551eae2955f54ee4b857f \ - --hash=sha256:8bfd95ef3b097f0cc86ade54eafefa1c8ed623aa01a26fbbdcd1a3650494dd11 \ - --hash=sha256:8d8143a3e3966f85dce6c5cc45387ec36552174ba5712c5dc6fcc0898fb324c0 \ - --hash=sha256:941596d419b9736ab548aa0feb5bbba922f98872668847bf0720b42d1d227b9e \ - --hash=sha256:941c4869aa229d88706b78187d60d66aca77fe5c32518b79e3c3e03fc26109a2 \ - --hash=sha256:9a1c84560b3b2d34695c9ba53ab0264e2802721c530678a8f0a227951f453462 \ - --hash=sha256:9e6a8f3d6c41e6b642870afe6cafbaf7b61c57317f9ec66d0efdaf19db992b90 \ - --hash=sha256:a6c71575a2fedf259724981fd73a18906513d2f306169c46262a5bae956e6364 \ - --hash=sha256:a8422dc13ad93ec8caa2612b5032a2b9cd6421c13ed87f54db4a3a2c93afaf77 \ - --hash=sha256:aaf3c54419a28d45bd1681372029f40e5bfb58e5265e3882eaf21e4a5f81a119 \ - --hash=sha256:b12c1aa7b95abe73b3e04e052c8b362655b41c7798da69f1eaf8d186c7d204df \ - --hash=sha256:b590f1ad056294dfaeac0b7e1b71d3d5ace638d8dd1f1147ce4bd13458783ba8 \ - --hash=sha256:bbb46330cc643ecf10bd9bd4ca8e7419a14b6b9dedd05f671c90fb2c813c6037 \ - --hash=sha256:ca931de5dd6d9eb94ff19a2c9434b23923bce6f767179fef04dfa991f282eaad \ - --hash=sha256:cb5175f45c980ff418998723ea1b3869cce3766d2ab4e4916fbd3cedbc9d0ed3 \ - --hash=sha256:d827a6fb9215b961eb73459ad7977edb9e748b23e3407d21c845d1d8ef6597e5 \ - --hash=sha256:dbb64b4166362d9326f7efbf75b1c72106c1aa87f13a8c8b56a1224fac152f5c \ - --hash=sha256:de5b6be29116e094c5ef9d9e4252e7eb143e3d5f6bd6d50a78075553ab4930b0 \ - --hash=sha256:e4a3cdba62b2d6aeae6027ae65f350de6dc082b72e6215eccf82628e79efe9ba \ - --hash=sha256:e75acfa52daf5ea0712e8aa82f0003bba964de7ae22c26d208cbd7bc08500177 \ - --hash=sha256:f40cebe5edb518d78b8131e87cb83b3ee688984de38a232024b9b44e74ee53d3 \ - --hash=sha256:f62652ddcadc75d0e7aa629e96bb61658f85a993e748333715b4ab667192e4e8 \ - --hash=sha256:ff5a84907e51924973aa05ed8759210d8cdae7ffcf9e44fd17646cf4a902df59 - # via - # -r requirements.in - # grpcio-tools -grpcio-tools==1.65.1 \ - --hash=sha256:004232fa8ef82298eeb01b391d708b3a89317910e2f7c623b566aea0448c8dcc \ - --hash=sha256:013017df92d6165e1556a17c618cf22471ef131fb614b428683730968b54b46d \ - --hash=sha256:074fce3b96a5c59ed526bdd07c04c6243c07b13278388837a0540840ae10bf5b \ - --hash=sha256:16f2f49048c76a68a8171507c39652c8be9ed4e7408deb9877002813aea4c396 \ - --hash=sha256:196e12c18f0ebe5ac7f5446fc1daef8d9c69ba40a987a1f8379bfdf6c32e54af \ - --hash=sha256:1ab64a9af7ce0aeb639a77423fa99de91863a0b8ce0e43fc50f57fc460a0d30e \ - --hash=sha256:1d8671d82449206ef040756a14484b0c5189615a0aac5f4734ad3d023d07d4b1 \ - --hash=sha256:1ece34ebb677a869606200812653f274757844754f0b684e59d61244b194f002 \ - --hash=sha256:24cffe8bc90fb8237f0bcf240bd6c70304255fe27b69db32601499a043f871be \ - --hash=sha256:257decc1782b9adca422a2625663529be64018c056d7346d8bbc7c9bf0fe3b80 \ - --hash=sha256:2ec7e376f3f53e7ab90614d5a2404c19c7902750bcc5bed8219ab864f9bc1c4b \ - --hash=sha256:3135888461888dcc7b358c17d60f32654cb36daf02bb805c84c0f8ab550743eb \ - --hash=sha256:32fa16e64f4b1684ed634155af9b03fdeabdf641d484e53c453e592e0f574f03 \ - --hash=sha256:33e4c602221f91c1d87c4574c496621f11826d4f8867f31f4c4c2ff1b144a777 \ - --hash=sha256:4887af67ff130174fa7fb420ee985d38659a7c960053639de28980003fe710eb \ - --hash=sha256:4b0714458a6a3a1ed587271f3e7c301b735ccbdd7946071a1d85a6d0aabcb57a \ - --hash=sha256:4dde0d90f96e29670c58a08aeeac61da49792f71602cb7421943be8918857a2a \ - --hash=sha256:5c9b4d95d2623b8b9435103305c3d375f8b4a266ee6fbbf29b5f4a57a8405047 \ - --hash=sha256:68d14cbd135541366bbef18c1d463f5d560878629f1901cae03777dad87755d9 \ - --hash=sha256:6f75bf562057723818dff7bf4e05884c220653ead3db19effe5873ce88c7cfd2 \ - --hash=sha256:7813a67cb427847e1a88d4fd4cbabfd2ed272455bd78b4f417377361d3b8edbd \ - --hash=sha256:881ccc523a171235bb6b1d8e965c2f11e525b54eb1d66aeb8fea5a72f84d6e02 \ - --hash=sha256:8d5a12e0bd2a0f33af11e11d89f19cddea66568716b53b77f3f5dc605ceb32e0 \ - --hash=sha256:9b6dbddca8e399ad96d263b786d0803acc67194cb80d01117691a9f239ac8dc9 \ - --hash=sha256:9cc6f342b8e8a2aa801d2d1640290a47563d8bb1a802671191dc3fc218747da3 \ - --hash=sha256:a89203d864dd024c4a13032f2df792eb465c63c224f9b82460d53f0cf30a3d16 \ - --hash=sha256:a95fd13dc17b065a934f00a0b99078de7773d4743772312efc8e75521ab62f7b \ - --hash=sha256:ac8cc2684bcde43296cf5a350b80b73713610f0789ff912c88f898ef065a0b6c \ - --hash=sha256:b6e45377dbe50c7a737d81620841b8c3f3a1650c76cb56a87b5b0414d10f9987 \ - --hash=sha256:b8ef108fceabb12ed29f750f2cb4827d7bad5033dc13596ad0de092f015f5123 \ - --hash=sha256:b8fe0bd8e63a4dd84c022ccbb6057e9f3c338e036a1b95c2a6dbcc928c35b4f9 \ - --hash=sha256:bc55edf7a0af0ad7384887845b6498fdb1a75d3633d11807f953cac531a34588 \ - --hash=sha256:bfb1a5e429756cdc9ce7183cca24a90bd7e68626379c83ea065bb30125d7aca4 \ - --hash=sha256:c394cf5b77eb71ff5c0ab857877f59dfee080cc95fb24d47e97d3965aaaf3c64 \ - --hash=sha256:c50895d383d41a379f9a235ce6d14c6639f36d43bf71c7148bf8a114a8f0936a \ - --hash=sha256:d4afb3e74c7a567eabda3c447421eb8fb5c6cbf19bb9292319056beff4ab49a1 \ - --hash=sha256:d99945dc53daa7987ae8c33227f96697ccc4d0a4a1ca6c366e28fcc9fc1c55fb \ - --hash=sha256:dc904f0de72eecbd024c111caa3e3165522349ff3c89361e4cbf06035c93061a \ - --hash=sha256:e24819f8d11fc9e6bad1e13a1d7fddd6027ed2a1aad583f093cfe027852ff3f9 \ - --hash=sha256:e44c69c029614fc61da2701587299fe19e52031aa1fba2a69a02c2dd77f903fe \ - --hash=sha256:e859001e20d4199ac90979e11d0d0ecb83f6b0235b08f8bfae93c2bd1401795a \ - --hash=sha256:edb4731b4ad068c3c48d52bbfa1404236cbcdd2524eb01a655e8adfadc2f0034 \ - --hash=sha256:ee1353c741f8f2fcf4fcce8764d4570e2d7c3025cc4c918a0c6532c18b6cbac5 \ - --hash=sha256:f49acf17ae7b1a35b5e0e5907ed9b70c042b3e7ab8769ea9fd26f20b2b888743 \ - --hash=sha256:fabbc0698cf0c614059c3e103b06c74d07190e9c7518f457703e98617ed467c0 \ - --hash=sha256:fd2fe61d40e7421dc64c90912e29c05f1c419dd7a90452c84a1b456e06bd8530 - # via -r requirements.in -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 - # via requests -protobuf==5.27.2 \ - --hash=sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505 \ - --hash=sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b \ - --hash=sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38 \ - --hash=sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863 \ - --hash=sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470 \ - --hash=sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6 \ - --hash=sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce \ - --hash=sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca \ - --hash=sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5 \ - --hash=sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e \ - --hash=sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714 - # via - # -r requirements.in - # grpcio-tools -requests==2.32.3 \ - --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ - --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 - # via -r requirements.in -urllib3==2.2.2 \ - --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ - --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 - # via requests - -# The following packages are considered to be unsafe in a requirements file: -setuptools==70.0.0 \ - --hash=sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4 \ - --hash=sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0 - # via grpcio-tools diff --git a/examples/grpc-bridge/docker-compose-protos.yaml b/examples/grpc-bridge/docker-compose-protos.yaml deleted file mode 100644 index 77dae2cb7e36..000000000000 --- a/examples/grpc-bridge/docker-compose-protos.yaml +++ /dev/null @@ -1,22 +0,0 @@ -services: - - # $ docker run -ti -v $(pwd):/protos -v $(pwd)/stubs:/stubs grpc/go protoc --go_out=plugins=grpc:/stubs -I/protos /protos/kv.proto - stubs_go: - build: - context: . - dockerfile: Dockerfile-grpc-go - command: protoc --go_out=plugins=grpc:/stubs -I/protos /protos/kv.proto - volumes: - - ./protos:/protos - - ./server/kv:/stubs - - # $ docker run -ti -v $(pwd):/protos -v $(pwd)/stubs:/stubs grpc/python python -m grpc.tools.protoc \ - # --python_out=/stubs --grpc_python_out=/stubs -I/protos /protos/kv.proto - stubs_python: - build: - context: . - dockerfile: Dockerfile-grpc-python - command: python -m grpc.tools.protoc --python_out=/stubs --grpc_python_out=/stubs -I/protos /protos/kv.proto - volumes: - - ./protos:/protos - - ./client/kv:/stubs diff --git a/examples/grpc-bridge/docker-compose.yaml b/examples/grpc-bridge/docker-compose.yaml deleted file mode 100644 index 75f27fdee359..000000000000 --- a/examples/grpc-bridge/docker-compose.yaml +++ /dev/null @@ -1,34 +0,0 @@ -services: - - # Requires the build of the stubs first - grpc-server: - build: - context: server - dockerfile: ../../shared/golang/Dockerfile - target: golang-grpc-server - - grpc-server-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./server/envoy-proxy.yaml - - # Requires the build of the stubs first - grpc-client: - build: - context: client - dockerfile: ../../shared/python/Dockerfile - target: python-grpc-client - args: - PYTHON_REQUIREMENTS_FILE: requirements.txt - environment: - CLIENT_PROXY: http://grpc-client-proxy:9911 - PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python - - grpc-client-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./client/envoy-proxy.yaml diff --git a/examples/grpc-bridge/example.rst b/examples/grpc-bridge/example.rst deleted file mode 100644 index 54d2e7211173..000000000000 --- a/examples/grpc-bridge/example.rst +++ /dev/null @@ -1,139 +0,0 @@ -.. _install_sandboxes_grpc_bridge: - -gRPC bridge -=========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -The gRPC bridge sandbox is an example usage of Envoy's -:ref:`gRPC bridge filter `. - -This is an example of a key-value store where an ``http``-based client CLI, written in ``Python``, -updates a remote store, written in ``Go``, using the stubs generated for both languages. - -The client send messages through a proxy that upgrades the HTTP requests from ``http/1.1`` to ``http/2`` or -``http/3`` - -``[client](http/1.1) -> [client-egress-proxy](http/2) -> [server-ingress-proxy](http/2) -> [server]`` - -Another Envoy feature demonstrated in this example is Envoy's ability to do authority -base routing via its route configuration. - -Step 1: Generate the protocol stubs -*********************************** - -Change to the ``examples/grpc-bridge`` directory. - -A docker compose file is provided that generates the stubs for both ``client`` and ``server`` from the -specification in the ``protos`` directory. - -Inspecting the :download:`docker-compose-protos.yaml <_include/grpc-bridge/docker-compose-protos.yaml>` file, -you will see that it contains both the ``python`` and ``go`` gRPC protoc commands necessary for generating the -protocol stubs. - -Generate the stubs as follows: - -.. code-block:: console - - $ pwd - envoy/examples/grpc-bridge - $ docker compose -f docker-compose-protos.yaml up - Starting grpc-bridge_stubs_python_1 ... done - Starting grpc-bridge_stubs_go_1 ... done - Attaching to grpc-bridge_stubs_go_1, grpc-bridge_stubs_python_1 - grpc-bridge_stubs_go_1 exited with code 0 - grpc-bridge_stubs_python_1 exited with code 0 - -You may wish to clean up left over containers with the following command: - -.. code-block:: console - - $ docker container prune - -You can view the generated ``kv`` modules for both the client and server in their -respective directories: - -.. code-block:: console - - $ ls -la client/kv/kv_pb2.py - -rw-r--r-- 1 mdesales CORP\Domain Users 9527 Nov 6 21:59 client/kv/kv_pb2.py - - $ ls -la server/kv/kv.pb.go - -rw-r--r-- 1 mdesales CORP\Domain Users 9994 Nov 6 21:59 server/kv/kv.pb.go - -These generated ``python`` and ``go`` stubs can be included as external modules. - -Step 2: Start all of our containers -*********************************** - -To build this sandbox example and start the example services, run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/grpc-bridge - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------------------- - grpc-bridge_grpc-client-proxy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:9911->9911/tcp - grpc-bridge_grpc-client_1 /bin/sh -c tail -f /dev/null Up - grpc-bridge_grpc-server-proxy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8811->8811/tcp - grpc-bridge_grpc-server_1 /bin/sh -c /bin/server Up 0.0.0.0:8081->8081/tcp - -Step 3: Send requests to the Key/Value store -******************************************** - -To use the Python service and send gRPC requests: - -.. code-block:: console - - $ pwd - envoy/examples/grpc-bridge - -Set a key: - -.. code-block:: console - - $ docker compose exec grpc-client python /client/grpc-kv-client.py set foo bar - setf foo to bar - - -Get a key: - -.. code-block:: console - - $ docker compose exec grpc-client python /client/grpc-kv-client.py get foo - bar - -Modify an existing key: - -.. code-block:: console - - $ docker compose exec grpc-client python /client/grpc-kv-client.py set foo baz - setf foo to baz - -Get the modified key: - -.. code-block:: console - - $ docker compose exec grpc-client python /client/grpc-kv-client.py get foo - baz - -In the running docker compose container, you should see the gRPC service printing a record of its activity: - -.. code-block:: console - - $ docker compose logs grpc-server - grpc_1 | 2017/05/30 12:05:09 set: foo = bar - grpc_1 | 2017/05/30 12:05:12 get: foo - grpc_1 | 2017/05/30 12:05:18 set: foo = baz - -.. seealso:: - - :ref:`gRPC bridge filter `. - Learn more about configuring Envoy's gRPC bridge filter. diff --git a/examples/grpc-bridge/protos/kv.proto b/examples/grpc-bridge/protos/kv.proto deleted file mode 100644 index 584e89b4f271..000000000000 --- a/examples/grpc-bridge/protos/kv.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; - -package kv; - -message GetRequest { - string key = 1; -} - -message GetResponse { - string value = 1; -} - -message SetRequest { - string key = 1; - string value = 2; -} - -message SetResponse { - bool ok = 1; -} - -service KV { - rpc Get(GetRequest) returns (GetResponse); - rpc Set(SetRequest) returns (SetResponse); -} diff --git a/examples/grpc-bridge/server/envoy-proxy.yaml b/examples/grpc-bridge/server/envoy-proxy.yaml deleted file mode 100644 index f007a85dc5e0..000000000000 --- a/examples/grpc-bridge/server/envoy-proxy.yaml +++ /dev/null @@ -1,51 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8811 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - grpc: {} - route: - cluster: backend_grpc_service - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: backend_grpc_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: backend_grpc_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: grpc-server - port_value: 8081 diff --git a/examples/grpc-bridge/server/go.mod b/examples/grpc-bridge/server/go.mod deleted file mode 100644 index ef7577426982..000000000000 --- a/examples/grpc-bridge/server/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/envoyproxy/envoy/examples/grpc-bridge/server - -go 1.13 - -require ( - github.com/golang/protobuf v1.5.4 - golang.org/x/net v0.26.0 - google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/grpc v1.64.1 -) diff --git a/examples/grpc-bridge/server/go.sum b/examples/grpc-bridge/server/go.sum deleted file mode 100644 index 2edc00714b2c..000000000000 --- a/examples/grpc-bridge/server/go.sum +++ /dev/null @@ -1,2642 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= -cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= -cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= -cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= -cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= -cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8= -cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= -cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/accesscontextmanager v1.8.2/go.mod h1:E6/SCRM30elQJ2PKtFMs2YhfJpZSNcJyejhuzoId4Zk= -cloud.google.com/go/accesscontextmanager v1.8.3/go.mod h1:4i/JkF2JiFbhLnnpnfoTX5vRXfhf9ukhU1ANOTALTOQ= -cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= -cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.50.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.0/go.mod h1:IRc2b8XAMTa9ZmfJV1BCCQbieWWvDnP1A8znyz5N7y4= -cloud.google.com/go/aiplatform v1.51.1/go.mod h1:kY3nIMAVQOK2XDqDPHaOuD9e+FdMA6OOpfBjsvaFSOo= -cloud.google.com/go/aiplatform v1.51.2/go.mod h1:hCqVYB3mY45w99TmetEoe8eCQEwZEp9WHxeZdcv9phw= -cloud.google.com/go/aiplatform v1.52.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.54.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.57.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= -cloud.google.com/go/aiplatform v1.58.2/go.mod h1:c3kCiVmb6UC1dHAjZjcpDj6ZS0bHQ2slL88ZjC2LtlA= -cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.4/go.mod h1:zZgNCxLCy8b2rKKVfC1YkC2vTrpfZmeRCySM3aUbskA= -cloud.google.com/go/analytics v0.21.5/go.mod h1:BQtOBHWTlJ96axpPPnw5CvGJ6i3Ve/qX2fTxR8qWyr8= -cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/analytics v0.22.0/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= -cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigateway v1.6.2/go.mod h1:CwMC90nnZElorCW63P2pAYm25AtQrHfuOkbRSHj0bT8= -cloud.google.com/go/apigateway v1.6.3/go.mod h1:k68PXWpEs6BVDTtnLQAyG606Q3mz8pshItwPXjgv44Y= -cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= -cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeconnect v1.6.2/go.mod h1:s6O0CgXT9RgAxlq3DLXvG8riw8PYYbU/v25jqP3Dy18= -cloud.google.com/go/apigeeconnect v1.6.3/go.mod h1:peG0HFQ0si2bN15M6QSjEW/W7Gy3NYkWGz7pFz13cbo= -cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= -cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apigeeregistry v0.7.2/go.mod h1:9CA2B2+TGsPKtfi3F7/1ncCCsL62NXBRfM6iPoGSM+8= -cloud.google.com/go/apigeeregistry v0.8.1/go.mod h1:MW4ig1N4JZQsXmBSwH4rwpgDonocz7FPBSw6XPGHmYw= -cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= -cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/appengine v1.8.2/go.mod h1:WMeJV9oZ51pvclqFN2PqHoGnys7rK0rz6s3Mp6yMvDo= -cloud.google.com/go/appengine v1.8.3/go.mod h1:2oUPZ1LVZ5EXi+AF1ihNAF+S8JrzQ3till5m9VQkrsk= -cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= -cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/area120 v0.8.2/go.mod h1:a5qfo+x77SRLXnCynFWPUZhnZGeSgvQ+Y0v1kSItkh4= -cloud.google.com/go/area120 v0.8.3/go.mod h1:5zj6pMzVTH+SVHljdSKC35sriR/CVvQZzG/Icdyriw0= -cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= -cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/artifactregistry v1.14.2/go.mod h1:Xk+QbsKEb0ElmyeMfdHAey41B+qBq3q5R5f5xD4XT3U= -cloud.google.com/go/artifactregistry v1.14.3/go.mod h1:A2/E9GXnsyXl7GUvQ/2CjHA+mVRoWAXC0brg2os+kNI= -cloud.google.com/go/artifactregistry v1.14.4/go.mod h1:SJJcZTMv6ce0LDMUnihCN7WSrI+kBSFV0KIKo8S8aYU= -cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= -cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/asset v1.15.0/go.mod h1:tpKafV6mEut3+vN9ScGvCHXHj7FALFVta+okxFECHcg= -cloud.google.com/go/asset v1.15.1/go.mod h1:yX/amTvFWRpp5rcFq6XbCxzKT8RJUam1UoboE179jU4= -cloud.google.com/go/asset v1.15.2/go.mod h1:B6H5tclkXvXz7PD22qCA2TDxSVQfasa3iDlM89O2NXs= -cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.16.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.17.0/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= -cloud.google.com/go/asset v1.17.1/go.mod h1:byvDw36UME5AzGNK7o4JnOnINkwOZ1yRrGrKIahHrng= -cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/assuredworkloads v1.11.2/go.mod h1:O1dfr+oZJMlE6mw0Bp0P1KZSlj5SghMBvTpZqIcUAW4= -cloud.google.com/go/assuredworkloads v1.11.3/go.mod h1:vEjfTKYyRUaIeA0bsGJceFV2JKpVRgyG2op3jfa59Zs= -cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= -cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= -cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY= -cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= -cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/baremetalsolution v1.2.0/go.mod h1:68wi9AwPYkEWIUT4SvSGS9UJwKzNpshjHsH4lzk8iOw= -cloud.google.com/go/baremetalsolution v1.2.1/go.mod h1:3qKpKIw12RPXStwQXcbhfxVj1dqQGEvcmA+SX/mUR88= -cloud.google.com/go/baremetalsolution v1.2.2/go.mod h1:O5V6Uu1vzVelYahKfwEWRMaS3AbCkeYHy3145s1FkhM= -cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= -cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/batch v1.4.1/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.0/go.mod h1:KdBmDD61K0ovcxoRHGrN6GmOBWeAOyCgKD0Mugx4Fkk= -cloud.google.com/go/batch v1.5.1/go.mod h1:RpBuIYLkQu8+CWDk3dFD/t/jOCGuUpkpX+Y0n1Xccs8= -cloud.google.com/go/batch v1.6.1/go.mod h1:urdpD13zPe6YOK+6iZs/8/x2VBRofvblLpx0t57vM98= -cloud.google.com/go/batch v1.6.3/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.7.0/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= -cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.1/go.mod h1:zl/rWWAFVeV+kx+X2Javly7o1EIQThU4WlkynffL/lk= -cloud.google.com/go/beyondcorp v1.0.2/go.mod h1:m8cpG7caD+5su+1eZr+TSvF6r21NdLJk4f9u4SP2Ntc= -cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= -cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.55.0/go.mod h1:9Y5I3PN9kQWuid6183JFhOGOW3GcirA5LpsKCUn+2ec= -cloud.google.com/go/bigquery v1.56.0/go.mod h1:KDcsploXTEY7XT3fDQzMUZlpQLHzE4itubHrnmhUrZA= -cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= -cloud.google.com/go/bigquery v1.58.0/go.mod h1:0eh4mWNY0KrBTjUzLjoYImapGORq9gEPT7MWjCy9lik= -cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/billing v1.17.0/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.1/go.mod h1:Z9+vZXEq+HwH7bhJkyI4OQcR6TSbeMrjlpEjO2vzY64= -cloud.google.com/go/billing v1.17.2/go.mod h1:u/AdV/3wr3xoRBk5xvUzYMS1IawOAPwQMuHgHMdljDg= -cloud.google.com/go/billing v1.17.3/go.mod h1:z83AkoZ7mZwBGT3yTnt6rSGI1OOsHSIi6a5M3mJ8NaU= -cloud.google.com/go/billing v1.17.4/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.0/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= -cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/binaryauthorization v1.7.0/go.mod h1:Zn+S6QqTMn6odcMU1zDZCJxPjU2tZPV1oDl45lWY154= -cloud.google.com/go/binaryauthorization v1.7.1/go.mod h1:GTAyfRWYgcbsP3NJogpV3yeunbUIjx2T9xVeYovtURE= -cloud.google.com/go/binaryauthorization v1.7.2/go.mod h1:kFK5fQtxEp97m92ziy+hbu+uKocka1qRRL8MVJIgjv0= -cloud.google.com/go/binaryauthorization v1.7.3/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.0/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= -cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/certificatemanager v1.7.2/go.mod h1:15SYTDQMd00kdoW0+XY5d9e+JbOPjp24AvF48D8BbcQ= -cloud.google.com/go/certificatemanager v1.7.3/go.mod h1:T/sZYuC30PTag0TLo28VedIRIj1KPGcOQzjWAptHa00= -cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= -cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/channel v1.17.0/go.mod h1:RpbhJsGi/lXWAUM1eF4IbQGbsfVlg2o8Iiy2/YLfVT0= -cloud.google.com/go/channel v1.17.1/go.mod h1:xqfzcOZAcP4b/hUDH0GkGg1Sd5to6di1HOJn/pi5uBQ= -cloud.google.com/go/channel v1.17.2/go.mod h1:aT2LhnftnyfQceFql5I/mP8mIbiiJS4lWqgXA815zMk= -cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/channel v1.17.4/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= -cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.14.1/go.mod h1:K7wGc/3zfvmYWOWwYTgF/d/UVJhS4pu+HAy7PL7mCsU= -cloud.google.com/go/cloudbuild v1.14.2/go.mod h1:Bn6RO0mBYk8Vlrt+8NLrru7WXlQ9/RDWz2uo5KG1/sg= -cloud.google.com/go/cloudbuild v1.14.3/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= -cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/clouddms v1.7.0/go.mod h1:MW1dC6SOtI/tPNCciTsXtsGNEM0i0OccykPvv3hiYeM= -cloud.google.com/go/clouddms v1.7.1/go.mod h1:o4SR8U95+P7gZ/TX+YbJxehOCsM+fe6/brlrFquiszk= -cloud.google.com/go/clouddms v1.7.2/go.mod h1:Rk32TmWmHo64XqDvW7jgkFQet1tUKNVzs7oajtJT3jU= -cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= -cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.2/go.mod h1:A7nYkjNlW2gUoROg1kvJrQGhJP/38UaWwsnuBDOBVUk= -cloud.google.com/go/cloudtasks v1.12.3/go.mod h1:GPVXhIOSGEaR+3xT4Fp72ScI+HjHffSS4B8+BaBB5Ys= -cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= -cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= -cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= -cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= -cloud.google.com/go/contactcenterinsights v1.11.1/go.mod h1:FeNP3Kg8iteKM80lMwSk3zZZKVxr+PGnAId6soKuXwE= -cloud.google.com/go/contactcenterinsights v1.11.2/go.mod h1:A9PIR5ov5cRcd28KlDbmmXE8Aay+Gccer2h4wzkYFso= -cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.0/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.12.1/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= -cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.26.0/go.mod h1:YJCmRet6+6jnYYRS000T6k0D0xUXQgBSaJ7VwI8FBj4= -cloud.google.com/go/container v1.26.1/go.mod h1:5smONjPRUxeEpDG7bMKWfDL4sauswqEtnBK1/KKpR04= -cloud.google.com/go/container v1.26.2/go.mod h1:YlO84xCt5xupVbLaMY4s3XNE79MUJ+49VmkInr6HvF4= -cloud.google.com/go/container v1.27.1/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.28.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.29.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= -cloud.google.com/go/container v1.30.1/go.mod h1:vkbfX0EnAKL/vgVECs5BZn24e1cJROzgszJirRKQ4Bg= -cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/containeranalysis v0.11.0/go.mod h1:4n2e99ZwpGxpNcz+YsFT1dfOHPQFGcAC8FN2M2/ne/U= -cloud.google.com/go/containeranalysis v0.11.1/go.mod h1:rYlUOM7nem1OJMKwE1SadufX0JP3wnXj844EtZAwWLY= -cloud.google.com/go/containeranalysis v0.11.2/go.mod h1:xibioGBC1MD2j4reTyV1xY1/MvKaz+fyM9ENWhmIeP8= -cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= -cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.17.1/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.0/go.mod h1:nCSYFHgtxh2MiEktWIz71s/X+7ds/UT9kp0PC7waCzE= -cloud.google.com/go/datacatalog v1.18.1/go.mod h1:TzAWaz+ON1tkNr4MOcak8EBHX7wIRX/gZKM+yTVsv+A= -cloud.google.com/go/datacatalog v1.18.2/go.mod h1:SPVgWW2WEMuWHA+fHodYjmxPiMqcOiWfhc9OD5msigk= -cloud.google.com/go/datacatalog v1.18.3/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= -cloud.google.com/go/datacatalog v1.19.2/go.mod h1:2YbODwmhpLM4lOFe3PuEhHK9EyTzQJ5AXgIy7EDKTEE= -cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataflow v0.9.2/go.mod h1:vBfdBZ/ejlTaYIGB3zB4T08UshH70vbtZeMD+urnUSo= -cloud.google.com/go/dataflow v0.9.3/go.mod h1:HI4kMVjcHGTs3jTHW/kv3501YW+eloiJSLxkJa/vqFE= -cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= -cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/dataform v0.8.2/go.mod h1:X9RIqDs6NbGPLR80tnYoPNiO1w0wenKTb8PxxlhTMKM= -cloud.google.com/go/dataform v0.8.3/go.mod h1:8nI/tvv5Fso0drO3pEjtowz58lodx8MVkdV2q0aPlqg= -cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= -cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datafusion v1.7.2/go.mod h1:62K2NEC6DRlpNmI43WHMWf9Vg/YvN6QVi8EVwifElI0= -cloud.google.com/go/datafusion v1.7.3/go.mod h1:eoLt1uFXKGBq48jy9LZ+Is8EAVLnmn50lNncLzwYokE= -cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= -cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/datalabeling v0.8.2/go.mod h1:cyDvGHuJWu9U/cLDA7d8sb9a0tWLEletStu2sTmg3BE= -cloud.google.com/go/datalabeling v0.8.3/go.mod h1:tvPhpGyS/V7lqjmb3V0TaDdGvhzgR1JoW7G2bpi2UTI= -cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= -cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.10.1/go.mod h1:1MzmBv8FvjYfc7vDdxhnLFNskikkB+3vl475/XdCDhs= -cloud.google.com/go/dataplex v1.10.2/go.mod h1:xdC8URdTrCrZMW6keY779ZT1cTOfV8KEPNsw+LTRT1Y= -cloud.google.com/go/dataplex v1.11.1/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.11.2/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.13.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.14.0/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= -cloud.google.com/go/dataplex v1.14.1/go.mod h1:bWxQAbg6Smg+sca2+Ex7s8D9a5qU6xfXtwmq4BVReps= -cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataproc/v2 v2.2.0/go.mod h1:lZR7AQtwZPvmINx5J87DSOOpTfof9LVZju6/Qo4lmcY= -cloud.google.com/go/dataproc/v2 v2.2.1/go.mod h1:QdAJLaBjh+l4PVlVZcmrmhGccosY/omC1qwfQ61Zv/o= -cloud.google.com/go/dataproc/v2 v2.2.2/go.mod h1:aocQywVmQVF4i8CL740rNI/ZRpsaaC1Wh2++BJ7HEJ4= -cloud.google.com/go/dataproc/v2 v2.2.3/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= -cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= -cloud.google.com/go/dataqna v0.8.2/go.mod h1:KNEqgx8TTmUipnQsScOoDpq/VlXVptUqVMZnt30WAPs= -cloud.google.com/go/dataqna v0.8.3/go.mod h1:wXNBW2uvc9e7Gl5k8adyAMnLush1KVV6lZUhB+rqNu4= -cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= -cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.14.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.1/go.mod h1:7ngSYwnw95YFyTd5tOGBxHlOZiL+OtpjheqU7t2/s/c= -cloud.google.com/go/datastream v1.10.2/go.mod h1:W42TFgKAs/om6x/CdXX5E4oiAsKlH+e8MTGy81zdYt0= -cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= -cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.1/go.mod h1:8jeadyLkH9qu9xgO3hVWw8jVr29N1mnW42gRJT8GY6g= -cloud.google.com/go/deploy v1.14.1/go.mod h1:N8S0b+aIHSEeSr5ORVoC0+/mOPUysVt8ae4QkZYolAw= -cloud.google.com/go/deploy v1.14.2/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.15.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.16.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= -cloud.google.com/go/deploy v1.17.0/go.mod h1:XBr42U5jIr64t92gcpOXxNrqL2PStQCXHuKK5GRUuYo= -cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.43.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.0/go.mod h1:pDUJdi4elL0MFmt1REMvFkdsUTYSHq+rTCS8wg0S3+M= -cloud.google.com/go/dialogflow v1.44.1/go.mod h1:n/h+/N2ouKOO+rbe/ZnI186xImpqvCVj2DdsWS/0EAk= -cloud.google.com/go/dialogflow v1.44.2/go.mod h1:QzFYndeJhpVPElnFkUXxdlptx0wPnBWLCBT9BvtC3/c= -cloud.google.com/go/dialogflow v1.44.3/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.47.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.48.0/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= -cloud.google.com/go/dialogflow v1.48.1/go.mod h1:C1sjs2/g9cEwjCltkKeYp3FFpz8BOzNondEaAlCpt+A= -cloud.google.com/go/dialogflow v1.48.2/go.mod h1:7A2oDf6JJ1/+hdpnFRfb/RjJUOh2X3rhIa5P8wQSEX4= -cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/dlp v1.10.2/go.mod h1:ZbdKIhcnyhILgccwVDzkwqybthh7+MplGC3kZVZsIOQ= -cloud.google.com/go/dlp v1.10.3/go.mod h1:iUaTc/ln8I+QT6Ai5vmuwfw8fqTk2kaz0FvCwhLCom0= -cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= -cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.1/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.0/go.mod h1:LKs22aDHbJv7ufXuPypzRO7rG3ALLJxzdCXDPutw4Qc= -cloud.google.com/go/documentai v1.23.2/go.mod h1:Q/wcRT+qnuXOpjAkvOV4A+IeQl04q2/ReT7SSbytLSo= -cloud.google.com/go/documentai v1.23.4/go.mod h1:4MYAaEMnADPN1LPN5xboDR5QVB6AgsaxgFdJhitlE2Y= -cloud.google.com/go/documentai v1.23.5/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.6/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.7/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= -cloud.google.com/go/documentai v1.23.8/go.mod h1:Vd/y5PosxCpUHmwC+v9arZyeMfTqBR9VIwOwIqQYYfA= -cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/domains v0.9.2/go.mod h1:3YvXGYzZG1Temjbk7EyGCuGGiXHJwVNmwIf+E/cUp5I= -cloud.google.com/go/domains v0.9.3/go.mod h1:29k66YNDLDY9LCFKpGFeh6Nj9r62ZKm5EsUJxAl84KU= -cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= -cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/edgecontainer v1.1.2/go.mod h1:wQRjIzqxEs9e9wrtle4hQPSR1Y51kqN75dgF7UllZZ4= -cloud.google.com/go/edgecontainer v1.1.3/go.mod h1:Ll2DtIABzEfaxaVSbwj3QHFaOOovlDFiWVDu349jSsA= -cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= -cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/essentialcontacts v1.6.3/go.mod h1:yiPCD7f2TkP82oJEFXFTou8Jl8L6LBRPeBEkTaO0Ggo= -cloud.google.com/go/essentialcontacts v1.6.4/go.mod h1:iju5Vy3d9tJUg0PYMd1nHhjV7xoCXaOAVabrwLaPBEM= -cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= -cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.1/go.mod h1:EqBxmGHFrruIara4FUQ3RHlgfCn7yo1HYsu2Hpt/C3Y= -cloud.google.com/go/eventarc v1.13.2/go.mod h1:X9A80ShVu19fb4e5sc/OLV7mpFUKZMwfJFeeWhcIObM= -cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= -cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/filestore v1.7.2/go.mod h1:TYOlyJs25f/omgj+vY7/tIG/E7BX369triSPzE4LdgE= -cloud.google.com/go/filestore v1.7.3/go.mod h1:Qp8WaEERR3cSkxToxFPHh/b8AACkSut+4qlCjAmKTV0= -cloud.google.com/go/filestore v1.7.4/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= -cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.12.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8= -cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/functions v1.15.2/go.mod h1:CHAjtcR6OU4XF2HuiVeriEdELNcnvRZSk1Q8RMqy4lE= -cloud.google.com/go/functions v1.15.3/go.mod h1:r/AMHwBheapkkySEhiZYLDBwVJCdlRwsm4ieJu35/Ug= -cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= -cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.1/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkebackup v1.3.2/go.mod h1:OMZbXzEJloyXMC7gqdSB+EOEQ1AKcpGYvO3s1ec5ixk= -cloud.google.com/go/gkebackup v1.3.3/go.mod h1:eMk7/wVV5P22KBakhQnJxWSVftL1p4VBFLpv0kIft7I= -cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= -cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkeconnect v0.8.2/go.mod h1:6nAVhwchBJYgQCXD2pHBFQNiJNyAd/wyxljpaa6ZPrY= -cloud.google.com/go/gkeconnect v0.8.3/go.mod h1:i9GDTrfzBSUZGCe98qSu1B8YB8qfapT57PenIb820Jo= -cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= -cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkehub v0.14.2/go.mod h1:iyjYH23XzAxSdhrbmfoQdePnlMj2EWcvnR+tHdBQsCY= -cloud.google.com/go/gkehub v0.14.3/go.mod h1:jAl6WafkHHW18qgq7kqcrXYzN08hXeK/Va3utN8VKg8= -cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= -cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.1/go.mod h1:AcrGoin6VLKT/fwZEYuqvVominLriQBCKmbjtnbMjG8= -cloud.google.com/go/gkemulticloud v1.0.2/go.mod h1:+ee5VXxKb3H1l4LZAcgWB/rvI16VTNTrInWxDjAGsGo= -cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/gkemulticloud v1.1.0/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= -cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/grafeas v0.3.4/go.mod h1:A5m316hcG+AulafjAbPKXBO/+I5itU4LOdKO2R/uDIc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/gsuiteaddons v1.6.2/go.mod h1:K65m9XSgs8hTF3X9nNTPi8IQueljSdYo9F+Mi+s4MyU= -cloud.google.com/go/gsuiteaddons v1.6.3/go.mod h1:sCFJkZoMrLZT3JTb8uJqgKPNshH2tfXeCwTFRebTq48= -cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= -cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= -cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= -cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= -cloud.google.com/go/iap v1.9.2/go.mod h1:GwDTOs047PPSnwRD0Us5FKf4WDRcVvHg1q9WVkKBhdI= -cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= -cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/ids v1.4.2/go.mod h1:3vw8DX6YddRu9BncxuzMyWn0g8+ooUjI2gslJ7FH3vk= -cloud.google.com/go/ids v1.4.3/go.mod h1:9CXPqI3GedjmkjbMWCUhMZ2P2N7TUMzAkVXYEH2orYU= -cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= -cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/iot v1.7.2/go.mod h1:q+0P5zr1wRFpw7/MOgDXrG/HVA+l+cSwdObffkrpnSg= -cloud.google.com/go/iot v1.7.3/go.mod h1:t8itFchkol4VgNbHnIq9lXoOOtHNR3uAACQMYbN9N4I= -cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= -cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= -cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ= -cloud.google.com/go/kms v1.15.4/go.mod h1:L3Sdj6QTHK8dfwK5D1JLsAyELsNMnd3tAIwGS4ltKpc= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= -cloud.google.com/go/kms v1.15.6/go.mod h1:yF75jttnIdHfGBoE51AKsD/Yqf+/jICzB9v1s1acsms= -cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/language v1.11.0/go.mod h1:uDx+pFDdAKTY8ehpWbiXyQdz8tDSYLJbQcXsCkjYyvQ= -cloud.google.com/go/language v1.11.1/go.mod h1:Xyid9MG9WOX3utvDbpX7j3tXDmmDooMyMDqgUVpH17U= -cloud.google.com/go/language v1.12.1/go.mod h1:zQhalE2QlQIxbKIZt54IASBzmZpN/aDASea5zl1l+J4= -cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= -cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/lifesciences v0.9.2/go.mod h1:QHEOO4tDzcSAzeJg7s2qwnLM2ji8IRpQl4p6m5Z9yTA= -cloud.google.com/go/lifesciences v0.9.3/go.mod h1:gNGBOJV80IWZdkd+xz4GQj4mbqaz737SCLHn2aRhQKM= -cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= -cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= -cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs= -cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y= -cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= -cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4= -cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= -cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/maps v1.3.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/maps v1.4.1/go.mod h1:BxSa0BnW1g2U2gNdbq5zikLlHUuHW0GFWh7sgML2kIY= -cloud.google.com/go/maps v1.5.1/go.mod h1:NPMZw1LJwQZYCfz4y+EIw+SI+24A4bpdFJqdKVr0lt4= -cloud.google.com/go/maps v1.6.1/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.2/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= -cloud.google.com/go/maps v1.6.3/go.mod h1:VGAn809ADswi1ASofL5lveOHPnE6Rk/SFTTBx1yuOLw= -cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/mediatranslation v0.8.2/go.mod h1:c9pUaDRLkgHRx3irYE5ZC8tfXGrMYwNZdmDqKMSfFp8= -cloud.google.com/go/mediatranslation v0.8.3/go.mod h1:F9OnXTy336rteOEywtY7FOqCk+J43o2RF638hkOQl4Y= -cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= -cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/memcache v1.10.2/go.mod h1:f9ZzJHLBrmd4BkguIAa/l/Vle6uTHzHokdnzSWOdQ6A= -cloud.google.com/go/memcache v1.10.3/go.mod h1:6z89A41MT2DVAW0P4iIRdu5cmRTsbsFn4cyiIx8gbwo= -cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= -cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.13.0/go.mod h1:URDhpG6XLeh5K+Glq0NOt74OfrPKTwS62gEPZzb5SOk= -cloud.google.com/go/metastore v1.13.1/go.mod h1:IbF62JLxuZmhItCppcIfzBBfUFq0DIB9HPDoLgWrVOU= -cloud.google.com/go/metastore v1.13.2/go.mod h1:KS59dD+unBji/kFebVp8XU/quNSyo8b6N6tPGspKszA= -cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= -cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/monitoring v1.16.0/go.mod h1:Ptp15HgAyM1fNICAojDMoNc/wUmn67mLHQfyqbw+poY= -cloud.google.com/go/monitoring v1.16.1/go.mod h1:6HsxddR+3y9j+o/cMJH6q/KJ/CBTvM/38L/1m7bTRJ4= -cloud.google.com/go/monitoring v1.16.2/go.mod h1:B44KGwi4ZCF8Rk/5n+FWeispDXoKSk9oss2QNlXJBgc= -cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.0/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= -cloud.google.com/go/monitoring v1.17.1/go.mod h1:SJzPMakCF0GHOuKEH/r4hxVKF04zl+cRPQyc3d/fqII= -cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkconnectivity v1.13.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.0/go.mod h1:SAnGPes88pl7QRLUen2HmcBSE9AowVAcdug8c0RSBFk= -cloud.google.com/go/networkconnectivity v1.14.1/go.mod h1:LyGPXR742uQcDxZ/wv4EI0Vu5N6NKJ77ZYVnDe69Zug= -cloud.google.com/go/networkconnectivity v1.14.2/go.mod h1:5UFlwIisZylSkGG1AdwK/WZUaoz12PKu6wODwIbFzJo= -cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= -cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networkmanagement v1.9.0/go.mod h1:UTUaEU9YwbCAhhz3jEOHr+2/K/MrBk2XxOLS89LQzFw= -cloud.google.com/go/networkmanagement v1.9.1/go.mod h1:CCSYgrQQvW73EJawO2QamemYcOb57LvrDdDU51F0mcI= -cloud.google.com/go/networkmanagement v1.9.2/go.mod h1:iDGvGzAoYRghhp4j2Cji7sF899GnfGQcQRQwgVOWnDw= -cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= -cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/networksecurity v0.9.2/go.mod h1:jG0SeAttWzPMUILEHDUvFYdQTl8L/E/KC8iZDj85lEI= -cloud.google.com/go/networksecurity v0.9.3/go.mod h1:l+C0ynM6P+KV9YjOnx+kk5IZqMSLccdBqW6GUoF4p/0= -cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= -cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/notebooks v1.10.0/go.mod h1:SOPYMZnttHxqot0SGSFSkRrwE29eqnKPBJFqgWmiK2k= -cloud.google.com/go/notebooks v1.10.1/go.mod h1:5PdJc2SgAybE76kFQCWrTfJolCOUQXF97e+gteUUA6A= -cloud.google.com/go/notebooks v1.11.1/go.mod h1:V2Zkv8wX9kDCGRJqYoI+bQAaoVeE5kSiz4yYHd2yJwQ= -cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= -cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/optimization v1.5.0/go.mod h1:evo1OvTxeBRBu6ydPlrIRizKY/LJKo/drDMMRKqGEUU= -cloud.google.com/go/optimization v1.5.1/go.mod h1:NC0gnUD5MWVAF7XLdoYVPmYYVth93Q6BUzqAq3ZwtV8= -cloud.google.com/go/optimization v1.6.1/go.mod h1:hH2RYPTTM9e9zOiTaYPTiGPcGdNZVnBSBxjIAJzUkqo= -cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= -cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orchestration v1.8.2/go.mod h1:T1cP+6WyTmh6LSZzeUhvGf0uZVmJyTx7t8z7Vg87+A0= -cloud.google.com/go/orchestration v1.8.3/go.mod h1:xhgWAYqlbYjlz2ftbFghdyqENYW+JXuhBx9KsjMoGHs= -cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= -cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/orgpolicy v1.11.2/go.mod h1:biRDpNwfyytYnmCRWZWxrKF22Nkz9eNVj9zyaBdpm1o= -cloud.google.com/go/orgpolicy v1.11.3/go.mod h1:oKAtJ/gkMjum5icv2aujkP4CxROxPXsBbYGCDbPO8MM= -cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/orgpolicy v1.12.0/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= -cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/osconfig v1.12.2/go.mod h1:eh9GPaMZpI6mEJEuhEjUJmaxvQ3gav+fFEJon1Y8Iw0= -cloud.google.com/go/osconfig v1.12.3/go.mod h1:L/fPS8LL6bEYUi1au832WtMnPeQNT94Zo3FwwV1/xGM= -cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= -cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/oslogin v1.11.0/go.mod h1:8GMTJs4X2nOAUVJiPGqIWVcDaF0eniEto3xlOxaboXE= -cloud.google.com/go/oslogin v1.11.1/go.mod h1:OhD2icArCVNUxKqtK0mcSmKL7lgr0LVlQz+v9s1ujTg= -cloud.google.com/go/oslogin v1.12.1/go.mod h1:VfwTeFJGbnakxAY236eN8fsnglLiVXndlbcNomY4iZU= -cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= -cloud.google.com/go/oslogin v1.13.0/go.mod h1:xPJqLwpTZ90LSE5IL1/svko+6c5avZLluiyylMb/sRA= -cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/phishingprotection v0.8.2/go.mod h1:LhJ91uyVHEYKSKcMGhOa14zMMWfbEdxG032oT6ECbC8= -cloud.google.com/go/phishingprotection v0.8.3/go.mod h1:3B01yO7T2Ra/TMojifn8EoGd4G9jts/6cIO0DgDY9J8= -cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= -cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/policytroubleshooter v1.9.0/go.mod h1:+E2Lga7TycpeSTj2FsH4oXxTnrbHJGRlKhVZBLGgU64= -cloud.google.com/go/policytroubleshooter v1.9.1/go.mod h1:MYI8i0bCrL8cW+VHN1PoiBTyNZTstCg2WUw2eVC4c4U= -cloud.google.com/go/policytroubleshooter v1.10.1/go.mod h1:5C0rhT3TDZVxAu8813bwmTvd57Phbl8mr9F4ipOsxEs= -cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= -cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= -cloud.google.com/go/privatecatalog v0.9.2/go.mod h1:RMA4ATa8IXfzvjrhhK8J6H4wwcztab+oZph3c6WmtFc= -cloud.google.com/go/privatecatalog v0.9.3/go.mod h1:K5pn2GrVmOPjXz3T26mzwXLcKivfIJ9R5N79AFCF9UE= -cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= -cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.34.0/go.mod h1:alj4l4rBg+N3YTFDDC+/YyFTs6JAjam2QfYsddcAW4c= -cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.0/go.mod h1:QuE8EdU9dEnesG8/kG3XuJyNsjEqMlMzg3v3scCJ46c= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.1/go.mod h1:JZYZJOeZjgSSTGP4uz7NlQ4/d1w5hGmksVgM0lbEij0= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.2/go.mod h1:kpaDBOpkwD4G0GVMzG1W6Doy1tFFC97XAV3xy+Rd/pw= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.3/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.8.4/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.0/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= -cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommendationengine v0.8.2/go.mod h1:QIybYHPK58qir9CV2ix/re/M//Ty10OxjnnhWdaKS1Y= -cloud.google.com/go/recommendationengine v0.8.3/go.mod h1:m3b0RZV02BnODE9FeSvGv1qibFo8g0OnmB/RMwYy4V8= -cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= -cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/recommender v1.11.0/go.mod h1:kPiRQhPyTJ9kyXPCG6u/dlPLbYfFlkwHNRwdzPVAoII= -cloud.google.com/go/recommender v1.11.1/go.mod h1:sGwFFAyI57v2Hc5LbIj+lTwXipGu9NW015rkaEM5B18= -cloud.google.com/go/recommender v1.11.2/go.mod h1:AeoJuzOvFR/emIcXdVFkspVXVTYpliRCmKNYDnyBv6Y= -cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.0/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= -cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/redis v1.13.2/go.mod h1:0Hg7pCMXS9uz02q+LoEVl5dNHUkIQv+C/3L76fandSA= -cloud.google.com/go/redis v1.13.3/go.mod h1:vbUpCKUAZSYzFcWKmICnYgRAhTFg9r+djWqFxDYXi4U= -cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= -cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcemanager v1.9.2/go.mod h1:OujkBg1UZg5lX2yIyMo5Vz9O5hf7XQOSV7WxqxxMtQE= -cloud.google.com/go/resourcemanager v1.9.3/go.mod h1:IqrY+g0ZgLsihcfcmqSe+RKp1hzjXwG904B92AwBz6U= -cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= -cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/resourcesettings v1.6.2/go.mod h1:mJIEDd9MobzunWMeniaMp6tzg4I2GvD3TTmPkc8vBXk= -cloud.google.com/go/resourcesettings v1.6.3/go.mod h1:pno5D+7oDYkMWZ5BpPsb4SO0ewg3IXcmmrUZaMJrFic= -cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= -cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/retail v1.14.2/go.mod h1:W7rrNRChAEChX336QF7bnMxbsjugcOCPU44i5kbLiL8= -cloud.google.com/go/retail v1.14.3/go.mod h1:Omz2akDHeSlfCq8ArPKiBxlnRpKEBjUH386JYFLUvXo= -cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= -cloud.google.com/go/retail v1.15.1/go.mod h1:In9nSBOYhLbDGa87QvWlnE1XA14xBN2FpQRiRsUs9wU= -cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/run v1.3.0/go.mod h1:S/osX/4jIPZGg+ssuqh6GNgg7syixKe3YnprwehzHKU= -cloud.google.com/go/run v1.3.1/go.mod h1:cymddtZOzdwLIAsmS6s+Asl4JoXIDm/K1cpZTxV4Q5s= -cloud.google.com/go/run v1.3.2/go.mod h1:SIhmqArbjdU/D9M6JoHaAqnAMKLFtXaVdNeq04NjnVE= -cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= -cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/scheduler v1.10.2/go.mod h1:O3jX6HRH5eKCA3FutMw375XHZJudNIKVonSCHv7ropY= -cloud.google.com/go/scheduler v1.10.3/go.mod h1:8ANskEM33+sIbpJ+R4xRfw/jzOG+ZFE8WVLy7/yGvbc= -cloud.google.com/go/scheduler v1.10.4/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= -cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/secretmanager v1.11.2/go.mod h1:MQm4t3deoSub7+WNwiC4/tRYgDBHJgJPvswqQVB1Vss= -cloud.google.com/go/secretmanager v1.11.3/go.mod h1:0bA2o6FabmShrEy328i67aV+65XoUFFSmVeLBn/51jI= -cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= -cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/security v1.15.2/go.mod h1:2GVE/v1oixIRHDaClVbHuPcZwAqFM28mXuAKCfMgYIg= -cloud.google.com/go/security v1.15.3/go.mod h1:gQ/7Q2JYUZZgOzqKtw9McShH+MjNvtDpL40J1cT+vBs= -cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= -cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/securitycenter v1.23.1/go.mod h1:w2HV3Mv/yKhbXKwOCu2i8bCuLtNP1IMHuiYQn4HJq5s= -cloud.google.com/go/securitycenter v1.24.1/go.mod h1:3h9IdjjHhVMXdQnmqzVnM7b0wMn/1O/U20eWVpMpZjI= -cloud.google.com/go/securitycenter v1.24.2/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.3/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= -cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.1/go.mod h1:tJywXimEWzNzw9FvtNjsQxxJ3/41jseeILgwU/QLrGI= -cloud.google.com/go/servicedirectory v1.11.2/go.mod h1:KD9hCLhncWRV5jJphwIpugKwM5bn1x0GyVVD4NO8mGg= -cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= -cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/shell v1.7.2/go.mod h1:KqRPKwBV0UyLickMn0+BY1qIyE98kKyI216sH/TuHmc= -cloud.google.com/go/shell v1.7.3/go.mod h1:cTTEz/JdaBsQAeTQ3B6HHldZudFoYBOqjteev07FbIc= -cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= -cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/spanner v1.49.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.50.0/go.mod h1:eGj9mQGK8+hkgSVbHNQ06pQ4oS+cyc4tXXd6Dif1KoM= -cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0= -cloud.google.com/go/spanner v1.53.0/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.53.1/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= -cloud.google.com/go/spanner v1.54.0/go.mod h1:wZvSQVBgngF0Gq86fKup6KIYmN2be7uOKjtK97X+bQU= -cloud.google.com/go/spanner v1.55.0/go.mod h1:HXEznMUVhC+PC+HDyo9YFG2Ajj5BQDkcbqB9Z2Ffxi0= -cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= -cloud.google.com/go/spanner v1.57.0/go.mod h1:aXQ5QDdhPRIqVhYmnkAdwPYvj/DRN0FguclhEWw+jOo= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.1/go.mod h1:WcuaWz/3hOlzPFOVo9DUsblMIHwxP589y6ZMtaG+iAA= -cloud.google.com/go/speech v1.19.2/go.mod h1:2OYFfj+Ch5LWjsaSINuCZsre/789zlcCI3SY4oAi2oI= -cloud.google.com/go/speech v1.20.1/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= -cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= -cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k= -cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/storagetransfer v1.10.1/go.mod h1:rS7Sy0BtPviWYTTJVWCSV4QrbBitgPeuK4/FKa4IdLs= -cloud.google.com/go/storagetransfer v1.10.2/go.mod h1:meIhYQup5rg9juQJdyppnA/WLQCOguxtk1pr3/vBWzA= -cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= -cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/talent v1.6.3/go.mod h1:xoDO97Qd4AK43rGjJvyBHMskiEf3KulgYzcH6YWOVoo= -cloud.google.com/go/talent v1.6.4/go.mod h1:QsWvi5eKeh6gG2DlBkpMaFYZYrYUnIpo34f6/V5QykY= -cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= -cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/texttospeech v1.7.2/go.mod h1:VYPT6aTOEl3herQjFHYErTlSZJ4vB00Q2ZTmuVgluD4= -cloud.google.com/go/texttospeech v1.7.3/go.mod h1:Av/zpkcgWfXlDLRYob17lqMstGZ3GqlvJXqKMp2u8so= -cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= -cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/tpu v1.6.2/go.mod h1:NXh3NDwt71TsPZdtGWgAG5ThDfGd32X1mJ2cMaRlVgU= -cloud.google.com/go/tpu v1.6.3/go.mod h1:lxiueqfVMlSToZY1151IaZqp89ELPSrk+3HIQ5HRkbY= -cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= -cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/trace v1.10.2/go.mod h1:NPXemMi6MToRFcSxRl2uDnu/qAlAQ3oULUphcHGh1vA= -cloud.google.com/go/trace v1.10.3/go.mod h1:Ke1bgfc73RV3wUFml+uQp7EsDw4dGaETLxB7Iq/r4CY= -cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= -cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.0/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.9.1/go.mod h1:TWIgDZknq2+JD4iRcojgeDtqGEp154HN/uL6hMvylS8= -cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zNmqzXKHqRrY= -cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/translate v1.10.0/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= -cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.20.0/go.mod h1:U3G3FTnsvAGqglq9LxgqzOiBc/Nt8zis8S+850N2DUM= -cloud.google.com/go/video v1.20.1/go.mod h1:3gJS+iDprnj8SY6pe0SwLeC5BUW80NjhwX7INWEuWGU= -cloud.google.com/go/video v1.20.2/go.mod h1:lrixr5JeKNThsgfM9gqtwb6Okuqzfo4VrY2xynaViTA= -cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= -cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/videointelligence v1.11.2/go.mod h1:ocfIGYtIVmIcWk1DsSGOoDiXca4vaZQII1C85qtoplc= -cloud.google.com/go/videointelligence v1.11.3/go.mod h1:tf0NUaGTjU1iS2KEkGWvO5hRHeCkFK3nPo0/cOZhZAo= -cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= -cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vision/v2 v2.7.3/go.mod h1:V0IcLCY7W+hpMKXK1JYE0LV5llEqVmj+UJChjvA1WsM= -cloud.google.com/go/vision/v2 v2.7.4/go.mod h1:ynDKnsDN/0RtqkKxQZ2iatv3Dm9O+HfRb5djl7l4Vvw= -cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= -cloud.google.com/go/vision/v2 v2.7.6/go.mod h1:ZkvWTVNPBU3YZYzgF9Y1jwEbD1NBOCyJn0KFdQfE6Bw= -cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmmigration v1.7.2/go.mod h1:iA2hVj22sm2LLYXGPT1pB63mXHhrH1m/ruux9TwWLd8= -cloud.google.com/go/vmmigration v1.7.3/go.mod h1:ZCQC7cENwmSWlwyTrZcWivchn78YnFniEQYRWQ65tBo= -cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= -cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.1/go.mod h1:aT3Xsm5sNx0QShk1Jc1B8OddrxAScYLwzVoaiXfdzzk= -cloud.google.com/go/vmwareengine v1.0.2/go.mod h1:xMSNjIk8/itYrz1JA8nV3Ajg4L4n3N+ugP8JKzk3OaA= -cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= -cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/vpcaccess v1.7.2/go.mod h1:mmg/MnRHv+3e8FJUjeSibVFvQF1cCy2MsFaFqxeY1HU= -cloud.google.com/go/vpcaccess v1.7.3/go.mod h1:YX4skyfW3NC8vI3Fk+EegJnlYFatA+dXK4o236EUCUc= -cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= -cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd/5uQIPBc= -cloud.google.com/go/webrisk v1.9.3/go.mod h1:RUYXe9X/wBDXhVilss7EDLW9ZNa06aowPuinUOPCXH8= -cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= -cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= -cloud.google.com/go/websecurityscanner v1.6.3/go.mod h1:x9XANObUFR+83Cya3g/B9M/yoHVqzxPnFtgF8yYGAXw= -cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= -cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -cloud.google.com/go/workflows v1.12.0/go.mod h1:PYhSk2b6DhZ508tj8HXKaBh+OFe+xdl0dHF/tJdzPQM= -cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= -cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmnAzK/CnBqsHc= -cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= -cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= -github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/arrow/go/v12 v12.0.1/go.mod h1:weuTY7JvTG/HDPtMQxEUp7pU73vkLWMLpY67QwZ/WWw= -github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/apache/thrift v0.17.0/go.mod h1:OLxhMRJxomX+1I/KUw03qoV3mMz16BwaKI+d4fPBx7Q= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= -github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= -github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-pkcs11 v0.2.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= -google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= -google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= -google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= -google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= -google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= -google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= -google.golang.org/api v0.166.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= -google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto v0.0.0-20230821184602-ccc8af3d0e93/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= -google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:PVreiBMirk8ypES6aw9d4p6iiBNSIfZEBqr3UGoAi2E= -google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0/go.mod h1:guYXGPwC6jwxgWKW5Y405fKWOFNwlvUlUnzyp9i0uqo= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:ZSvZ8l+AWJwXw91DoTjWjaVLpWU6o0eZ4YLYpH8aLeQ= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:SCz6T5xjNXM4QFPRwxHcfChp7V+9DcXR3ay2TkHR8Tg= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240205150955-31a09d347014/go.mod h1:EhZbXt+eY4Yr3YVaEGLdNZF5viWowOJZ8KTPqjYMKzg= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:om8Bj876Z0v9ei+RD1LnEWig7vpHQ371PUqsgjmLQEA= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240122161410-6c6643bf1457/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228201840-1f18d85a4ec2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.2/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/libc v1.22.4/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/tcl v1.15.1/go.mod h1:aEjeGJX2gz1oWKOLDVZ2tnEWLUrIn8H+GFu+akoDhqs= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/examples/grpc-bridge/server/kv/empty.go b/examples/grpc-bridge/server/kv/empty.go deleted file mode 100644 index d0c265a0e2af..000000000000 --- a/examples/grpc-bridge/server/kv/empty.go +++ /dev/null @@ -1,8 +0,0 @@ -// make the kv module is not empty, make go mod tidy happy. -// a kv.pb.go file will be generated by protoc, while running the example. -// also, introduce the empty.go file to import the protobuf package, -// which will be imported from the generated kv.pb.go file. - -package kv - -import _ "github.com/golang/protobuf/proto" diff --git a/examples/grpc-bridge/server/service.go b/examples/grpc-bridge/server/service.go deleted file mode 100644 index 80a335e8f927..000000000000 --- a/examples/grpc-bridge/server/service.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net" - - "sync" - - "github.com/envoyproxy/envoy/examples/grpc-bridge/server/kv" - "golang.org/x/net/context" - "google.golang.org/grpc" -) - -type KV struct { - sync.Mutex - store map[string]string -} - -func (k *KV) Get(ctx context.Context, in *kv.GetRequest) (*kv.GetResponse, error) { - log.Printf("get: %s", in.Key) - resp := new(kv.GetResponse) - if val, ok := k.store[in.Key]; ok { - resp.Value = val - } - - return resp, nil -} - -func (k *KV) Set(ctx context.Context, in *kv.SetRequest) (*kv.SetResponse, error) { - log.Printf("set: %s = %s", in.Key, in.Value) - k.Lock() - defer k.Unlock() - - k.store[in.Key] = in.Value - - return &kv.SetResponse{Ok: true}, nil -} - -func NewKVStore() (kv *KV) { - kv = &KV{ - store: make(map[string]string), - } - - return -} - -func main() { - port := flag.Int("port", 8081, "grpc port") - - flag.Parse() - - lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - gs := grpc.NewServer() - kv.RegisterKVServer(gs, NewKVStore()) - - log.Printf("starting grpc on :%d\n", *port) - - gs.Serve(lis) -} diff --git a/examples/grpc-bridge/verify.sh b/examples/grpc-bridge/verify.sh deleted file mode 100755 index 29527f93dc2b..000000000000 --- a/examples/grpc-bridge/verify.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e - -export NAME=grpc-bridge -# this allows us to bring up the stack manually after generating stubs -export MANUAL=true - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Generate protocol stubs" -"${DOCKER_COMPOSE[@]}" -f docker-compose-protos.yaml up --quiet-pull --build - -ls client/kv/kv_pb2.py -ls server/kv/kv.pb.go - -bring_up_example - -run_log "Set key value foo=bar" -"${DOCKER_COMPOSE[@]}" exec -T grpc-client /client/grpc-kv-client.py set foo bar | grep setf - -run_log "Get key foo" -"${DOCKER_COMPOSE[@]}" exec -T grpc-client /client/grpc-kv-client.py get foo | grep bar diff --git a/examples/gzip/README.md b/examples/gzip/README.md deleted file mode 100644 index 8f8a87470044..000000000000 --- a/examples/gzip/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/gzip.html) diff --git a/examples/gzip/docker-compose.yaml b/examples/gzip/docker-compose.yaml deleted file mode 100644 index a6241e2c18ed..000000000000 --- a/examples/gzip/docker-compose.yaml +++ /dev/null @@ -1,18 +0,0 @@ -services: - - envoy-stats: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - service: - condition: service_healthy - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_STATS0:-9901}:9901" - - "${PORT_STATS1:-9902}:9902" - - service: - build: - context: ../shared/python - target: aiohttp-data-service diff --git a/examples/gzip/envoy.yaml b/examples/gzip/envoy.yaml deleted file mode 100644 index 06cb2ee23d72..000000000000 --- a/examples/gzip/envoy.yaml +++ /dev/null @@ -1,129 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - application/json - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip - memory_level: 3 - window_bits: 10 - - name: envoy.filters.http.decompressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor - decompressor_library: - name: upload - typed_config: - "@type": "type.googleapis.com/envoy.extensions.compression.gzip.decompressor.v3.Gzip" - window_bits: 9 - chunk_size: 8192 - # If this ratio is set too low, then body data will not be decompressed completely. - max_inflate_ratio: 1000 - response_direction_config: - common_config: - enabled: - default_value: false - runtime_key: response_decompressor_enabled - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - address: - socket_address: - address: 0.0.0.0 - port_value: 9902 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/stats/prometheus" - route: - cluster: envoy-stats - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - text/plain - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip - memory_level: 3 - window_bits: 10 - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: envoy-stats - connect_timeout: 0.25s - type: STATIC - load_assignment: - cluster_name: envoy-stats - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 9901 - - name: service - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 9901 diff --git a/examples/gzip/example.rst b/examples/gzip/example.rst deleted file mode 100644 index 1ae54eec39e4..000000000000 --- a/examples/gzip/example.rst +++ /dev/null @@ -1,124 +0,0 @@ -.. _install_sandboxes_gzip: - -Gzip -==== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -By enabling compression in Envoy you can save some network bandwidth, at the expense of increased processor usage. - -Envoy supports compression and decompression for both requests and responses. - -This sandbox provides examples of response compression and request decompression served over ``HTTP``. Although ``HTTPS`` is not demonstrated, compression can be used for this also. - -The sandbox covers three scenarios: - -- compression of files from an upstream server -- decompression of files from a downstream client -- compression of Envoy's own statistics - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/gzip`` directory and bring up the docker composition. - -.. code-block:: console - - $ pwd - envoy/examples/gzip - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - gzip_envoy-stats_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp, 0.0.0.0:9901->9901/tcp,:::9901->9901/tcp, 0.0.0.0:9902->9902/tcp,:::9902->9902/tcp - gzip_service_1 python3 /code/service.py Up (healthy) - -Step 2: Test Envoy’s compression of upstream files -************************************************** - -The sandbox is configured with two endpoints on port ``10000`` for serving upstream files: - -- ``/file.txt`` -- ``/file.json`` - -Only ``/file.json`` is configured to be compressed. - -Use ``curl`` to check that the response from requesting ``file.json`` contains the ``content-encoding: gzip`` header. - -You will need to add an ``accept-encoding: gzip`` request header. - -.. code-block:: console - - $ curl -si -H "Accept-Encoding: gzip" localhost:10000/file.json | grep "content-encoding" - content-encoding: gzip - -As only files with a content-type of ``application/json`` are configured to be gzipped, the response from requesting ``file.txt`` should not contain the ``content-encoding: gzip`` header, and the file will not be compressed: - -.. code-block:: console - - $ curl -si -H "Accept-Encoding: gzip" localhost:10000/file.txt | grep "content-encoding" - -Step 3: Test Envoy’s decompression of downstream files -****************************************************** - -The sandbox is configured with an endpoint for uploading downstream files: - -- ``/upload`` - -Use ``curl`` to get the compressed file ``file.gz`` - -.. code-block:: console - - $ curl -s -H "Accept-Encoding: gzip" -o file.gz localhost:10000/file.json - -Use ``curl`` to check that the response from uploading ``file.gz`` contains the ``decompressed-size`` header. - -You will need to add the ``content-encoding: gzip`` request header. - -.. code-block:: console - - $ curl -si -H "Content-Encoding: gzip" localhost:10000/upload --data-binary "@file.gz" | grep "decompressed-size" - decompressed-size: 10485760 - -Step 4: Test compression of Envoy’s statistics -********************************************** - -The sandbox is configured with two ports serving Envoy’s admin and statistics interface: - -- ``9901`` exposes the standard admin interface -- ``9902`` exposes a compressed version of the admin interface - -Use ``curl`` to make a request for uncompressed statistics on port ``9901``, it should not contain the ``content-encoding`` header in the response: - -.. code-block:: console - - $ curl -si -H "Accept-Encoding: gzip" localhost:9901/stats/prometheus | grep "content-encoding" - -Now, use ``curl`` to make a request for the compressed statistics: - -.. code-block:: console - - $ curl -si -H "Accept-Encoding: gzip" localhost:9902/stats/prometheus | grep "content-encoding" - content-encoding: gzip - -.. seealso:: - :ref:`Gzip Compression API ` - API and configuration reference for Envoy's gzip compression. - - :ref:`Gzip Decompression API ` - API and configuration reference for Envoy's gzip decompression. - - :ref:`Compression configuration ` - Reference documentation for Envoy's compressor filter. - - :ref:`Decompression configuration ` - Reference documentation for Envoy's decompressor filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/gzip/verify.sh b/examples/gzip/verify.sh deleted file mode 100755 index 3ff8fe01760e..000000000000 --- a/examples/gzip/verify.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -e - -export NAME=gzip -export PORT_PROXY="${GZIP_PORT_PROXY:-10700}" -export PORT_STATS0="${GZIP_PORT_STATS0:-10701}" -export PORT_STATS1="${GZIP_PORT_STATS1:-10702}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test service: localhost:${PORT_PROXY}/file.json with compression" -responds_with_header \ - "content-encoding: gzip" \ - "http://localhost:${PORT_PROXY}/file.json" \ - -i -H "Accept-Encoding: gzip" - -run_log "Test service: localhost:${PORT_PROXY}/file.txt without compression" -responds_without_header \ - "content-encoding: gzip" \ - "http://localhost:${PORT_PROXY}/file.txt" \ - -i -H "Accept-Encoding: gzip" - -run_log "Test service: localhost:${PORT_PROXY}/upload with decompression" -curl -s -H "Accept-Encoding: gzip" -o file.gz "http://localhost:${PORT_PROXY}/file.json" -responds_with \ - "decompressed-size: 10485760" \ - "http://localhost:${PORT_PROXY}/upload" \ - -X POST -i -H "Content-Encoding: gzip" --data-binary "@file.gz" -rm file.gz - -run_log "Test service: localhost:${PORT_STATS0}/stats/prometheus without compression" -responds_without_header \ - "content-encoding: gzip" \ - "http://localhost:${PORT_STATS0}/stats/prometheus" \ - -i -H "Accept-Encoding: gzip" - -run_log "Test service: localhost:${PORT_STATS1}/stats/prometheus with compression" -responds_with_header \ - "content-encoding: gzip" \ - "http://localhost:${PORT_STATS1}/stats/prometheus" \ - -i -H "Accept-Encoding: gzip" diff --git a/examples/jaeger-tracing/README.md b/examples/jaeger-tracing/README.md deleted file mode 100644 index 5124026acd76..000000000000 --- a/examples/jaeger-tracing/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/jaeger_tracing) diff --git a/examples/jaeger-tracing/docker-compose.yaml b/examples/jaeger-tracing/docker-compose.yaml deleted file mode 100644 index 64e461fb8bb5..000000000000 --- a/examples/jaeger-tracing/docker-compose.yaml +++ /dev/null @@ -1,43 +0,0 @@ -services: - - # jaeger - front-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - service1: - condition: service_healthy - service2: - condition: service_healthy - jaeger: - condition: service_healthy - ports: - - "${PORT_PROXY:-10000}:8000" - - service1: - build: - context: ../shared/python - target: aiohttp-tracing-service3 - volumes: - - ./service1-envoy-jaeger.yaml:/etc/service-envoy.yaml - environment: - - SERVICE_NAME=1 - - service2: - build: - context: ../shared/python - target: aiohttp-tracing-service3 - volumes: - - ./service2-envoy-jaeger.yaml:/etc/service-envoy.yaml - environment: - - SERVICE_NAME=2 - - jaeger: - build: - context: . - dockerfile: ../shared/jaeger/Dockerfile - environment: - - COLLECTOR_ZIPKIN_HOST_PORT=9411 - ports: - - "${PORT_UI:-10000}:16686" diff --git a/examples/jaeger-tracing/envoy.yaml b/examples/jaeger-tracing/envoy.yaml deleted file mode 100644 index b83db10d6598..000000000000 --- a/examples/jaeger-tracing/envoy.yaml +++ /dev/null @@ -1,70 +0,0 @@ -node: - cluster: front-proxy - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - generate_request_id: true - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: jaeger - collector_endpoint: "/api/v2/spans" - shared_span_context: false - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service1 - decorator: - operation: checkAvailability - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - use_remote_address: true - clusters: - - name: service1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8000 - - name: jaeger - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: jaeger - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: jaeger - port_value: 9411 diff --git a/examples/jaeger-tracing/example.rst b/examples/jaeger-tracing/example.rst deleted file mode 100644 index 83c5bbf3a621..000000000000 --- a/examples/jaeger-tracing/example.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. _install_sandboxes_jaeger_tracing: - -Jaeger tracing -============== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -The Jaeger tracing sandbox demonstrates Envoy's :ref:`request tracing ` -capabilities using `Jaeger `_ as the tracing provider. This sandbox -is very similar to the front proxy architecture described above, with one difference: -service1 makes an API call to service2 before returning a response. -The three containers will be deployed inside a virtual network called ``envoymesh``. - -All incoming requests are routed via the front Envoy, which is acting as a reverse proxy -sitting on the edge of the ``envoymesh`` network. Port ``8000`` is exposed -by docker compose (see :download:`docker-compose.yaml <_include/jaeger-tracing/docker-compose.yaml>`). Notice that -all Envoys are configured to collect request traces (e.g., http_connection_manager/config/tracing setup in -:download:`envoy.yaml <_include/jaeger-tracing/envoy.yaml>`) and setup to propagate the spans generated -by the Jaeger tracer to a Jaeger cluster (trace driver setup -in :download:`envoy.yaml <_include/jaeger-tracing/envoy.yaml>`). - -Before routing a request to the appropriate service Envoy or the application, Envoy will take -care of generating the appropriate spans for tracing (parent/child context spans). -At a high-level, each span records the latency of upstream API calls as well as information -needed to correlate the span with other related spans (e.g., the trace ID). - -One of the most important benefits of tracing from Envoy is that it will take care of -propagating the traces to the Jaeger service cluster. However, in order to fully take advantage -of tracing, the application has to propagate trace headers that Envoy generates, while making -calls to other services. In the sandbox we have provided, the simple ``aiohttp`` app -(see trace function in :download:`examples/shared/python/tracing/service.py <_include/shared/python/tracing/service.py>`) acting as service1 propagates -the trace headers while making an outbound call to service2. - -Step 1: Build the sandbox -************************* - -To build this sandbox example, and start the example apps run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/jaeger-tracing - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - jaeger-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp - jaeger-tracing_jaeger_1 /go/bin/all-in-one-linux - ... Up 14250/tcp, 14268/tcp, 0.0.0.0:16686->16686/tcp, 5775/udp, 5778/tcp, 6831/udp, 6832/udp, 9411/tcp - jaeger-tracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp - jaeger-tracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp - -Step 2: Generate some load -************************** - -You can now send a request to service1 via the front-envoy as follows: - -.. code-block:: console - - $ curl -v localhost:8000/trace/1 - * Trying 192.168.99.100... - * Connected to 192.168.99.100 (192.168.99.100) port 8000 (#0) - > GET /trace/1 HTTP/1.1 - > Host: 192.168.99.100:8000 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 200 OK - < content-type: text/html; charset=utf-8 - < content-length: 89 - < x-envoy-upstream-service-time: 9 - < server: envoy - < date: Fri, 26 Aug 2018 19:39:19 GMT - < - Hello from behind Envoy (service 1)! hostname: f26027f1ce28 resolvedhostname: 172.19.0.6 - * Connection #0 to host 192.168.99.100 left intact - -Step 3: View the traces in Jaeger UI -************************************ - -Point your browser to http://localhost:16686 . You should see the Jaeger dashboard. -Set the service to "front-proxy" and hit 'Find Traces'. You should see traces from the front-proxy. -Click on a trace to explore the path taken by the request from front-proxy to service1 -to service2, as well as the latency incurred at each hop. - -.. seealso:: - - :ref:`Request tracing ` - Learn more about using Envoy's request tracing. - - `Jaeger `_ - Jaeger tracing website. diff --git a/examples/jaeger-tracing/service1-envoy-jaeger.yaml b/examples/jaeger-tracing/service1-envoy-jaeger.yaml deleted file mode 100644 index e8828675c01b..000000000000 --- a/examples/jaeger-tracing/service1-envoy-jaeger.yaml +++ /dev/null @@ -1,120 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: jaeger - collector_endpoint: "/api/v2/spans" - shared_span_context: false - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: service1_route - virtual_hosts: - - name: service1 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: local_service - decorator: - operation: checkAvailability - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - address: - socket_address: - address: 0.0.0.0 - port_value: 9000 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: jaeger - collector_endpoint: "/api/v2/spans" - shared_span_context: false - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: egress_http - route_config: - name: service2_route - virtual_hosts: - - name: service2 - domains: - - "*" - routes: - - match: - prefix: "/trace/2" - route: - cluster: service2 - decorator: - operation: checkStock - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: local_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 8080 - - name: service2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2 - port_value: 8000 - - name: jaeger - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: jaeger - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: jaeger - port_value: 9411 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/jaeger-tracing/service2-envoy-jaeger.yaml b/examples/jaeger-tracing/service2-envoy-jaeger.yaml deleted file mode 100644 index fba4635d154a..000000000000 --- a/examples/jaeger-tracing/service2-envoy-jaeger.yaml +++ /dev/null @@ -1,70 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: jaeger - collector_endpoint: "/api/v2/spans" - shared_span_context: false - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: service2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: local_service - decorator: - operation: checkStock - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: local_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 8080 - - name: jaeger - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: jaeger - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: jaeger - port_value: 9411 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/jaeger-tracing/verify.sh b/examples/jaeger-tracing/verify.sh deleted file mode 100755 index 9349c8f5280a..000000000000 --- a/examples/jaeger-tracing/verify.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e - -export NAME=jaeger-tracing -export PORT_PROXY="${JAEGER_PORT_PROXY:-11010}" -export PORT_UI="${JAEGER_PORT_UI:-11011}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -wait_for 10 bash -c "responds_with Hello http://localhost:${PORT_PROXY}/trace/1" - -run_log "Test services" -responds_with \ - Hello \ - "http://localhost:${PORT_PROXY}/trace/1" - -run_log "Test Jaeger UI" -responds_with \ - "" \ - "http://localhost:${PORT_UI}" diff --git a/examples/kafka/Dockerfile-kafka b/examples/kafka/Dockerfile-kafka deleted file mode 100644 index 08e3c37aab9e..000000000000 --- a/examples/kafka/Dockerfile-kafka +++ /dev/null @@ -1 +0,0 @@ -FROM confluentinc/cp-kafka:latest@sha256:161aa5a125ebf49a88732bb3f2d37aa7605d4b758434503b1472c445f3132dc9 diff --git a/examples/kafka/Dockerfile-zookeeper b/examples/kafka/Dockerfile-zookeeper deleted file mode 100644 index 85eab02adeca..000000000000 --- a/examples/kafka/Dockerfile-zookeeper +++ /dev/null @@ -1 +0,0 @@ -FROM confluentinc/cp-zookeeper:latest@sha256:f89d332ecee856fe0bf2f1f8d936cb2603c3339d6417a97743d9fdac310f6656 diff --git a/examples/kafka/README.md b/examples/kafka/README.md deleted file mode 100644 index 34c0a473e71c..000000000000 --- a/examples/kafka/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/kafka) diff --git a/examples/kafka/docker-compose.yaml b/examples/kafka/docker-compose.yaml deleted file mode 100644 index c07ead7cd307..000000000000 --- a/examples/kafka/docker-compose.yaml +++ /dev/null @@ -1,54 +0,0 @@ -services: - - kafka-client: - build: - context: . - dockerfile: Dockerfile-kafka - restart: "no" - deploy: - replicas: 0 - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_VARIANT: contrib-dev - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_ADMIN:-8001}:8001" - - kafka-server: - build: - context: . - dockerfile: Dockerfile-kafka - depends_on: - zookeeper: - condition: service_healthy - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - # This Kafka server instance sets up two listener sockets: - # - external one for client traffic (this traffic will go through Envoy proxy), - # - internal one for cluster traffic (if we add more brokers). - KAFKA_LISTENERS: INTERNAL://kafka-server:9092,EXTERNAL://kafka-server:10000 - # Advertised listener value needs to be equal to Envoy's listener - # (will make clients discovering this broker talk to it through Envoy). - KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka-server:9092,EXTERNAL://proxy:10000 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 - - zookeeper: - build: - context: . - dockerfile: Dockerfile-zookeeper - healthcheck: - test: ["CMD", "sh", "-c", "echo ruok | nc 127.0.0.1 2181 || exit -1"] - interval: 5s - timeout: 60s - retries: 120 - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - KAFKA_OPTS: "-Dzookeeper.4lw.commands.whitelist=ruok" diff --git a/examples/kafka/envoy.yaml b/examples/kafka/envoy.yaml deleted file mode 100644 index a0425882565f..000000000000 --- a/examples/kafka/envoy.yaml +++ /dev/null @@ -1,38 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 # Host that Kafka clients should connect to. - port_value: 10000 # Port that Kafka clients should connect to. - filter_chains: - - filters: - - name: envoy.filters.network.kafka_broker - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.kafka_broker.v3.KafkaBroker - stat_prefix: kafka_broker - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - stat_prefix: kafka_service - cluster: kafka_service - - clusters: - - name: kafka_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: kafka_server - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - # Kafka server's listener for client traffic ('EXTERNAL'). - address: kafka-server - port_value: 10000 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/kafka/example.rst b/examples/kafka/example.rst deleted file mode 100644 index 7b522f2225c4..000000000000 --- a/examples/kafka/example.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _install_sandboxes_kafka: - -Kafka broker -============ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -This example demonstrates some basic operations with a Kafka broker proxied through Envoy. - -For your convenience, the :download:`composition <_include/kafka/docker-compose.yaml>` provides -a dockerized Kafka client. - -If you have the ``kafka-console-*`` binaries installed on your host system, you can instead follow -the examples using the host binary with ``--bootstrap-server localhost:10000``. - -Statistics collected by Envoy for the Kafka broker extension and related cluster metrics are also demonstrated. - - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/kafka`` directory. - -.. code-block:: console - - $ pwd - envoy/examples/kafka - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------- - kafka_kafka-server_1 /etc/confluent/docker/run Up 9092/tcp - kafka_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:8001->8001/tcp - kafka_zookeeper_1 /etc/confluent/docker/run Up (healthy) 2181/tcp, 2888/tcp, 3888/tcp - - -Step 2: Create a Kafka topic -**************************** - -Start by creating a Kafka topic with the name ``envoy-kafka-broker``: - -.. code-block:: console - - $ export TOPIC="envoy-kafka-broker" - $ docker compose run --rm kafka-client kafka-topics --bootstrap-server proxy:10000 --create --topic $TOPIC - - -Step 3: Check the Kafka topic -***************************** - -You can view the topics that Kafka is aware of with the ``kafka-topics --list`` argument. - -Check that the topic you created exists: - -.. code-block:: console - - $ docker compose run --rm kafka-client kafka-topics --bootstrap-server proxy:10000 --list | grep $TOPIC - - -Step 4: Send a message using the Kafka producer -*********************************************** - -Next, send a message for the topic you have created using the ``kafka-console-producer``: - -.. code-block:: console - - $ export MESSAGE="Welcome to Envoy and Kafka broker filter!" - $ docker compose run --rm kafka-client /bin/bash -c " \ - echo $MESSAGE \ - | kafka-console-producer --request-required-acks 1 --broker-list proxy:10000 --topic $TOPIC" - - -Step 5: Receive a message using the Kafka consumer -************************************************** - -Now you can receive the message using the ``kafka-console-consumer`` : - -.. code-block:: console - - $ docker compose run --rm kafka-client kafka-console-consumer --bootstrap-server proxy:10000 --topic $TOPIC --from-beginning --max-messages 1 | grep "$MESSAGE" - - -Step 6: Check admin ``kafka_broker`` stats -****************************************** - -When you proxy to the Kafka broker, Envoy records various stats. - -You can check the broker stats by querying the Envoy admin interface -(the numbers might differ a little as the kafka-client does not expose precise control over its network traffic): - -.. code-block:: console - - $ curl -s "http://localhost:8001/stats?filter=kafka.kafka_broker" | grep -v ": 0" | grep "_request:" - kafka.kafka_broker.request.api_versions_request: 9 - kafka.kafka_broker.request.create_topics_request: 1 - kafka.kafka_broker.request.fetch_request: 2 - kafka.kafka_broker.request.find_coordinator_request: 8 - kafka.kafka_broker.request.join_group_request: 2 - kafka.kafka_broker.request.leave_group_request: 1 - kafka.kafka_broker.request.list_offsets_request: 1 - kafka.kafka_broker.request.metadata_request: 12 - kafka.kafka_broker.request.offset_fetch_request: 1 - kafka.kafka_broker.request.produce_request: 1 - kafka.kafka_broker.request.sync_group_request: 1 - - -Step 7: Check admin ``kafka_service`` cluster stats -*************************************************** - -Envoy also records cluster stats for the Kafka service: - -.. code-block:: console - - $ curl -s "http://localhost:8001/stats?filter=cluster.kafka_service" | grep -v ": 0" - cluster.kafka_service.max_host_weight: 1 - cluster.kafka_service.membership_healthy: 1 - cluster.kafka_service.membership_total: 1 - -.. seealso:: - - :ref:`Envoy Kafka broker filter ` - Learn more about the Kafka broker filter. - - `Kafka `_ - The Apache Kafka. diff --git a/examples/kafka/verify.sh b/examples/kafka/verify.sh deleted file mode 100755 index efcf0f4afadd..000000000000 --- a/examples/kafka/verify.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -e - -export NAME=kafka -export PORT_PROXY="${KAFKA_PORT_PROXY:-11100}" -export PORT_ADMIN="${KAFKA_PORT_ADMIN:-11101}" - -# Explicitly specified the service want to start, since the `kafka-client` is expected to -# not start. -UPARGS="proxy kafka-server zookeeper" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -kafka_client () { - "${DOCKER_COMPOSE[@]}" run --rm kafka-client "$@" -} - -TOPIC="envoy-kafka-broker" - -MESSAGE="Welcome to Envoy and Kafka broker filter!" - -run_log "Create a Kafka topic" -kafka_client kafka-topics --bootstrap-server proxy:10000 --create --topic $TOPIC - -run_log "Check the Kafka topic" -kafka_client kafka-topics --bootstrap-server proxy:10000 --list | grep $TOPIC - -run_log "Send a message using the Kafka producer" -kafka_client /bin/bash -c " \ - echo $MESSAGE \ - | kafka-console-producer --request-required-acks 1 --broker-list proxy:10000 --topic $TOPIC" - -run_log "Receive a message using the Kafka consumer" -kafka_client kafka-console-consumer --bootstrap-server proxy:10000 --topic $TOPIC --from-beginning --max-messages 1 | grep "$MESSAGE" - -run_log "Check admin kafka_broker stats" - -# This function verifies whether a given metric exists and has a value > 0. -has_metric_with_at_least_1 () { - local stat response value - stat="$1" - shift - response=$(_curl "http://localhost:${PORT_ADMIN}/stats?filter=${stat}") - # Extract number from rows like 'kafka.kafka_broker.request.api_versions_request: 123'. - value=$(echo "${response}" | grep "${stat}:" | cut -f2 -d':' | tr -d ' ') - re='^[0-9]+$' - [[ ${value} =~ ${re} && ${value} -gt 0 ]] || { - echo "ERROR: metric check for [${stat}]" >&2 - echo "EXPECTED: numeric value greater than 0" >&2 - echo "RECEIVED:" >&2 - echo "${response}" >&2 - return 1 - } -} - -EXPECTED_BROKER_STATS=( - "kafka.kafka_broker.request.api_versions_request" - "kafka.kafka_broker.request.metadata_request" - "kafka.kafka_broker.request.create_topics_request" - "kafka.kafka_broker.request.produce_request" - "kafka.kafka_broker.request.fetch_request" - "kafka.kafka_broker.response.api_versions_response" - "kafka.kafka_broker.response.metadata_response" - "kafka.kafka_broker.response.create_topics_response" - "kafka.kafka_broker.response.produce_response" - "kafka.kafka_broker.response.fetch_response") -for stat in "${EXPECTED_BROKER_STATS[@]}"; do - has_metric_with_at_least_1 "${stat}" -done - -run_log "Check admin kafka_service stats" -EXPECTED_BROKER_STATS=( - "cluster.kafka_service.max_host_weight: 1" - "cluster.kafka_service.membership_healthy: 1" - "cluster.kafka_service.membership_total: 1") -for stat in "${EXPECTED_BROKER_STATS[@]}"; do - filter="$(echo "$stat" | cut -d: -f1)" - responds_with \ - "$stat" \ - "http://localhost:${PORT_ADMIN}/stats?filter=${filter}" -done diff --git a/examples/load-reporting-service/README.md b/examples/load-reporting-service/README.md deleted file mode 100644 index 10335ed5b4ee..000000000000 --- a/examples/load-reporting-service/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/load_reporting_service.html) diff --git a/examples/load-reporting-service/docker-compose.yaml b/examples/load-reporting-service/docker-compose.yaml deleted file mode 100644 index b18d2c0264e6..000000000000 --- a/examples/load-reporting-service/docker-compose.yaml +++ /dev/null @@ -1,27 +0,0 @@ -services: - - envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY0:-80}-${PORT_PROXY1:-81}:80" - - "${PORT_ADMIN:-8081}:8081" - depends_on: - http_service: - condition: service_healthy - lrs_server: - condition: service_started - - http_service: - build: - context: ../shared/python - target: aiohttp-tracing-service - - lrs_server: - build: - context: . - dockerfile: ../shared/golang/Dockerfile - target: golang-lrs - volumes: - - /go/src/github.com/envoyproxy/envoy/examples/load-reporting-service diff --git a/examples/load-reporting-service/envoy.yaml b/examples/load-reporting-service/envoy.yaml deleted file mode 100644 index 4e25a23fa31c..000000000000 --- a/examples/load-reporting-service/envoy.yaml +++ /dev/null @@ -1,69 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 80 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: service - domains: - - "*" - routes: - - match: - prefix: "/service" - route: - cluster: local_service - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: local_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: http_service - port_value: 8080 - - name: load_reporting_cluster - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: load_reporting_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: lrs_server - port_value: 18000 -cluster_manager: - load_stats_config: - api_type: GRPC - grpc_services: - - envoy_grpc: - cluster_name: load_reporting_cluster -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8081 diff --git a/examples/load-reporting-service/example.rst b/examples/load-reporting-service/example.rst deleted file mode 100644 index 0563ab8ca348..000000000000 --- a/examples/load-reporting-service/example.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. _install_sandboxes_load_reporting_service: - -Load reporting service (``LRS``) -================================ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -This simple example demonstrates Envoy's :ref:`Load reporting service (LRS) ` -capability and how to use it. - -Lets say Cluster A (downstream) talks to Cluster B (Upstream) and Cluster C (Upstream). When enabling Load Report for -Cluster A, LRS server should be sending LoadStatsResponse to Cluster A with LoadStatsResponse.Clusters to be B and C. -LRS server will then receive LoadStatsRequests (with total requests, successful requests etc) from Cluster A to Cluster B and -from Cluster A to Cluster C. - -In this example, all incoming requests are routed via Envoy to a simple goLang web server aka http_server. -We scale up two containers and randomly send requests to each. Envoy is configured to initiate the connection with LRS Server. -LRS Server enables the stats by sending LoadStatsResponse. Sending requests to http_server will be counted towards successful -requests and will be visible in LRS Server logs. - -Step 1: Build the sandbox -************************* - -Change to the ``examples/load-reporting-service`` directory. - -Terminal 1 :: - - $ pwd - envoy/examples/load-reporting-service - $ docker compose pull - $ docker compose up --scale http_service=2 - - -Terminal 2 :: - - $ pwd - envoy/examples/load_reporting_service - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------- - load-reporting-service_http_service_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:81->80/tcp - load-reporting-service_http_service_2 python3 /code/service.py ... Up (healthy) - load-reporting-service_lrs_server_1 go run main.go Up - -Step 2: Start sending stream of HTTP requests -********************************************* - -Terminal 2 :: - - $ pwd - envoy/examples/load_reporting_service - $ bash send_requests.sh - -The script above (:download:`send_requests.sh <_include/load-reporting-service/send_requests.sh>`) sends requests -randomly to each Envoy, which in turn forwards the requests to the backend service. - -Step 3: See Envoy Stats -*********************** - -You should see - -Terminal 1 :: - - ............................ - lrs_server_1 | 2020/02/12 17:08:20 LRS Server is up and running on :18000 - lrs_server_1 | 2020/02/12 17:08:23 Adding new cluster to cache `http_service` with node `0022a319e1e2` - lrs_server_1 | 2020/02/12 17:08:24 Adding new node `2417806c9d9a` to existing cluster `http_service` - lrs_server_1 | 2020/02/12 17:08:25 Creating LRS response for cluster http_service, node 2417806c9d9a with frequency 2 secs - lrs_server_1 | 2020/02/12 17:08:25 Creating LRS response for cluster http_service, node 0022a319e1e2 with frequency 2 secs - http_service_2 | 127.0.0.1 - - [12/Feb/2020 17:09:06] "GET /service HTTP/1.1" 200 - - http_service_1 | 127.0.0.1 - - [12/Feb/2020 17:09:06] "GET /service HTTP/1.1" 200 - - ............................ - lrs_server_1 | 2020/02/12 17:09:07 Got stats from cluster `http_service` node `0022a319e1e2` - cluster_name:"local_service" upstream_locality_stats: total_successful_requests:21 total_issued_requests:21 > load_report_interval: - lrs_server_1 | 2020/02/12 17:09:07 Got stats from cluster `http_service` node `2417806c9d9a` - cluster_name:"local_service" upstream_locality_stats: total_successful_requests:17 total_issued_requests:17 > load_report_interval: - http_service_2 | 127.0.0.1 - - [12/Feb/2020 17:09:07] "GET /service HTTP/1.1" 200 - - http_service_1 | 127.0.0.1 - - [12/Feb/2020 17:09:07] "GET /service HTTP/1.1" 200 - - ............................ - lrs_server_1 | 2020/02/12 17:09:09 Got stats from cluster `http_service` node `0022a319e1e2` - cluster_name:"local_service" upstream_locality_stats: total_successful_requests:3 total_issued_requests:3 > load_report_interval: - lrs_server_1 | 2020/02/12 17:09:09 Got stats from cluster `http_service` node `2417806c9d9a` - cluster_name:"local_service" upstream_locality_stats: total_successful_requests:9 total_issued_requests:9 > load_report_interval: - -.. seealso:: - - :ref:`Load reporting service ` - Overview of Envoy's Load reporting service. - - :ref:`Load reporting service API(V3) ` - The Load reporting service API. diff --git a/examples/load-reporting-service/go.mod b/examples/load-reporting-service/go.mod deleted file mode 100644 index 441ab451d9f8..000000000000 --- a/examples/load-reporting-service/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module github.com/envoyproxy/envoy/examples/load-reporting-service - -go 1.21 - -toolchain go1.22.5 - -require ( - github.com/envoyproxy/go-control-plane v0.12.0 - github.com/golang/protobuf v1.5.4 - google.golang.org/grpc v1.65.0 -) - -require ( - github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect - github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/protobuf v1.34.1 // indirect -) diff --git a/examples/load-reporting-service/go.sum b/examples/load-reporting-service/go.sum deleted file mode 100644 index 0af3b63c8b48..000000000000 --- a/examples/load-reporting-service/go.sum +++ /dev/null @@ -1,22 +0,0 @@ -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw= -github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= -github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/examples/load-reporting-service/main.go b/examples/load-reporting-service/main.go deleted file mode 100644 index d9e6800066e5..000000000000 --- a/examples/load-reporting-service/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "log" - "net" - - "github.com/envoyproxy/envoy/examples/load-reporting-service/server" - gcpLoadStats "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" - "google.golang.org/grpc" -) - -func main() { - // Listening on port 18000 - address := ":18000" - lis, err := net.Listen("tcp", address) - if err != nil { - panic(err) - } - - grpcServer := grpc.NewServer() - xdsServer := server.NewServer() - gcpLoadStats.RegisterLoadReportingServiceServer(grpcServer, xdsServer) - - log.Printf("LRS Server is up and running on %s", address) - err = grpcServer.Serve(lis) - if err != nil { - panic(err) - } -} diff --git a/examples/load-reporting-service/send_requests.sh b/examples/load-reporting-service/send_requests.sh deleted file mode 100644 index 70cede981862..000000000000 --- a/examples/load-reporting-service/send_requests.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -PORT_PROXY0=${PORT_PROXY0:-80} -PORT_PROXY1=${PORT_PROXY1:-81} - -counter=1 -while [ $counter -le 50 ] -do - # generate random Port number to send requests - ports=("${PORT_PROXY0}" "${PORT_PROXY1}") - port=${ports[$RANDOM % ${#ports[@]} ]} - - curl -v "localhost:${port}/service/load" - ((counter++)) -done diff --git a/examples/load-reporting-service/server/lrs_server.go b/examples/load-reporting-service/server/lrs_server.go deleted file mode 100644 index 9c662a94a5c3..000000000000 --- a/examples/load-reporting-service/server/lrs_server.go +++ /dev/null @@ -1,77 +0,0 @@ -package server - -import ( - "log" - "sync" - - gcpLoadStats "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" - "github.com/golang/protobuf/ptypes/duration" -) - -// This is how often Envoy will send the load report -const StatsFrequencyInSeconds = 2 - -// Server handling Load Stats communication -type Server interface { - gcpLoadStats.LoadReportingServiceServer - HandleRequest(stream gcpLoadStats.LoadReportingService_StreamLoadStatsServer, request *gcpLoadStats.LoadStatsRequest) -} - -func NewServer() Server { - return &server{nodesConnected: make(map[string]bool)} -} - -type server struct { - // protects nodesConnected - mu sync.Mutex - - // This cache stores nodes connected to the LRS server - nodesConnected map[string]bool -} - -// Handles incoming stream connections and LoadStatsRequests -func (s *server) StreamLoadStats(stream gcpLoadStats.LoadReportingService_StreamLoadStatsServer) error { - for { - req, err := stream.Recv() - // input stream ended or errored out - if err != nil { - return err - } - - s.HandleRequest(stream, req) - } -} - -func (s *server) HandleRequest(stream gcpLoadStats.LoadReportingService_StreamLoadStatsServer, request *gcpLoadStats.LoadStatsRequest) { - nodeID := request.GetNode().GetId() - - s.mu.Lock() - defer s.mu.Unlock() - - // Check whether any Node has already connected or not. - // If not, add the NodeID to nodesConnected and enable Load Report with given frequency - // If yes, log stats - if _, exist := s.nodesConnected[nodeID]; !exist { - // Add NodeID to the nodesConnected - log.Printf("Adding new new node to cache `%s`", nodeID) - s.nodesConnected[nodeID] = true - - // Initialize Load Reporting - err := stream.Send(&gcpLoadStats.LoadStatsResponse{ - Clusters: []string{"local_service"}, - LoadReportingInterval: &duration.Duration{Seconds: StatsFrequencyInSeconds}, - ReportEndpointGranularity: true, - }) - if err != nil { - log.Panicf("Unable to send response to node %s due to err: %s", nodeID, err) - } - return - } - - // After Load Report is enabled, log the Load Report stats received - for _, clusterStats := range request.ClusterStats { - if len(clusterStats.UpstreamLocalityStats) > 0 { - log.Printf("Got stats from cluster `%s` node `%s` - %s", request.Node.Cluster, request.Node.Id, clusterStats) - } - } -} diff --git a/examples/load-reporting-service/verify.sh b/examples/load-reporting-service/verify.sh deleted file mode 100755 index 48fb61050965..000000000000 --- a/examples/load-reporting-service/verify.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -e - -export NAME=load-reporting -export UPARGS="--scale http_service=2" -export PORT_PROXY0="${LRS_PORT_PROXY0:-11200}" -export PORT_PROXY1="${LRS_PORT_PROXY1:-11201}" -export PORT_ADMIN="${LRS_PORT_ADMIN:-11202}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Send requests" -bash send_requests.sh 2> /dev/null -run_log "Check logs: http 1" -"${DOCKER_COMPOSE[@]}" logs http_service | grep http_service-1 | grep HTTP | grep 200 - -run_log "Check logs: http 2" -"${DOCKER_COMPOSE[@]}" logs http_service | grep http_service-2 | grep HTTP | grep 200 - -wait_for 20 bash -c "${DOCKER_COMPOSE[*]} logs lrs_server | grep 'up and running'" - -run_log "Check logs: lrs_server" -"${DOCKER_COMPOSE[@]}" logs lrs_server | grep "up and running" - -run_log "Check logs: envoy is connect to lrs_server" -responds_with \ - upstream_rq_200 \ - "http://localhost:${PORT_ADMIN}/stats?filter=load_reporting_cluster" - -wait_for 10 bash -c "${DOCKER_COMPOSE[*]} logs lrs_server | grep 'Got stats from cluster'" - -run_log "Check logs: lrs_server works normally" -"${DOCKER_COMPOSE[@]}" logs lrs_server | grep "Got stats from cluster" - -# TODO(phlax): add some test/docs for interacting with load reporting server diff --git a/examples/local_ratelimit/Dockerfile-nginx b/examples/local_ratelimit/Dockerfile-nginx deleted file mode 100644 index fb92648942c4..000000000000 --- a/examples/local_ratelimit/Dockerfile-nginx +++ /dev/null @@ -1 +0,0 @@ -FROM nginx@sha256:6af79ae5de407283dcea8b00d5c37ace95441fd58a8b1d2aa1ed93f5511bb18c diff --git a/examples/local_ratelimit/README.md b/examples/local_ratelimit/README.md deleted file mode 100644 index a1e9c0a453fc..000000000000 --- a/examples/local_ratelimit/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/local_ratelimit.html) diff --git a/examples/local_ratelimit/docker-compose.yaml b/examples/local_ratelimit/docker-compose.yaml deleted file mode 100644 index 307dc5f1ebbf..000000000000 --- a/examples/local_ratelimit/docker-compose.yaml +++ /dev/null @@ -1,14 +0,0 @@ -services: - envoy-stat: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_STATS0:-9901}:9901" - - "${PORT_STATS1:-9902}:9902" - - service: - build: - context: . - dockerfile: Dockerfile-nginx diff --git a/examples/local_ratelimit/envoy.yaml b/examples/local_ratelimit/envoy.yaml deleted file mode 100644 index a81273a65ca4..000000000000 --- a/examples/local_ratelimit/envoy.yaml +++ /dev/null @@ -1,131 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 9902 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/stats/prometheus" - route: - cluster: envoy-stat - http_filters: - - name: envoy.filters.http.local_ratelimit - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit - stat_prefix: http_local_rate_limiter - token_bucket: - max_tokens: 2 - tokens_per_fill: 2 - fill_interval: 5s - filter_enabled: - runtime_key: local_rate_limit_enabled - default_value: - numerator: 100 - denominator: HUNDRED - filter_enforced: - runtime_key: local_rate_limit_enforced - default_value: - numerator: 100 - denominator: HUNDRED - response_headers_to_add: - - append_action: OVERWRITE_IF_EXISTS_OR_ADD - header: - key: x-local-rate-limit - value: 'true' - local_rate_limit_per_downstream_connection: false - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service - http_filters: - - name: envoy.filters.http.local_ratelimit - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit - stat_prefix: http_local_rate_limiter - token_bucket: - max_tokens: 2 - tokens_per_fill: 2 - fill_interval: 5s - filter_enabled: - runtime_key: local_rate_limit_enabled - default_value: - numerator: 100 - denominator: HUNDRED - filter_enforced: - runtime_key: local_rate_limit_enforced - default_value: - numerator: 100 - denominator: HUNDRED - response_headers_to_add: - - append_action: OVERWRITE_IF_EXISTS_OR_ADD - header: - key: x-local-rate-limit - value: 'true' - local_rate_limit_per_downstream_connection: false - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: envoy-stat - connect_timeout: 0.25s - type: STATIC - load_assignment: - cluster_name: envoy-stat - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 9901 - - name: service - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 80 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 9901 diff --git a/examples/local_ratelimit/example.rst b/examples/local_ratelimit/example.rst deleted file mode 100644 index 451d76ab1cf4..000000000000 --- a/examples/local_ratelimit/example.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. _install_sandboxes_ratelimit: - -Local Ratelimit -=============== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -Rate limiting is used to control the rate of requests sent or received by a network interface controller, which is helpful to prevent DoS attacks and limit web scraping. - -Envoy supports both local (non-distributed) and global rate limiting, and two types for local rate limiting: - -- L4 connections via the :ref:`local rate limit filter ` -- HTTP requests via the :ref:`HTTP local rate limit filter ` - -This sandbox provides an example of rate limiting of L4 connections. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/local_ratelimit`` directory and bring up the docker composition. - -.. code-block:: console - - $ pwd - envoy/examples/ratelimit - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - ratelimtit_envoy-stat_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp, 0.0.0.0:9901->9901/tcp,:::9901->9901/tcp, 0.0.0.0:9902->9902/tcp,:::9902->9902/tcp - ratelimtit_service_1 /docker-entrypoint.sh ngin ... Up 80/tcp - -Step 2: Test rate limiting of upstream service -********************************************** - -The sandbox is configured with ``10000`` port for upstream service. - -If a request reaches the rate limit, Envoy will add ``x-local-rate-limit`` header and refuse the connection with a 429 HTTP response code and with the content ``local_rate_limited``. - -Now, use ``curl`` to make a request five times for the limited upstream service: - -.. code-block:: console - - $ for i in {1..5}; do curl -si localhost:10000 | grep -E "x-local-rate-limit|429|local_rate_limited"; done - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - -The first two requests get responses, and the remaining requests are refused with expected responses. - - -Step 3: Test rate limiting of Envoy’s statistics -************************************************ - -The sandbox is configured with two ports serving Envoy’s admin and statistics interface: - -- ``9901`` exposes the standard admin interface -- ``9902`` exposes a rate limitied version of the admin interface - -Use ``curl`` to make a request five times for unlimited statistics on port ``9901``, it should not contain any rate limiting responses: - -.. code-block:: console - - $ for i in {1..5}; do curl -si localhost:9901/stats/prometheus | grep -E "x-local-rate-limit|429|local_rate_limited"; done - -Now, use ``curl`` to make a request five times for the limited statistics: - -.. code-block:: console - - $ for i in {1..5}; do curl -si localhost:9902/stats/prometheus | grep -E "x-local-rate-limit|429|local_rate_limited"; done - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - HTTP/1.1 429 Too Many Requests - x-local-rate-limit: true - local_rate_limited - -.. seealso:: - :ref:`global rate limiting ` - Reference documentation for Envoy's global rate limiting. diff --git a/examples/local_ratelimit/verify.sh b/examples/local_ratelimit/verify.sh deleted file mode 100755 index 973302230536..000000000000 --- a/examples/local_ratelimit/verify.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -e - -export NAME=local_ratelimit -export PORT_PROXY="${LOCAL_RATELIMIT_PORT_PROXY:-11210}" -export PORT_STATS0="${LOCAL_RATELIMIT_PORT_STATS0:-11211}" -export PORT_STATS1="${LOCAL_RATELIMIT_PORT_STATS1:-11212}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -responds_with_rate_limit () { - local count="$1" url="$2" - - for ((i=1;i<=count;i++)); do - responds_with \ - "local_rate_limited" \ - "$url" - done -} - -responds_without_rate_limit () { - local count="$1" url="$2" - - for ((i=1;i<=count;i++)); do - responds_without \ - "local_rate_limited" \ - "$url" - done -} -export -f responds_without_rate_limit - - -run_log "Test upstream: localhost:${PORT_PROXY} without rate limit header two times" -for i in {1..2}; do - output=$(curl -s -X GET --head "http://localhost:${PORT_PROXY}") - echo "${output}" | grep "429 Too Many Requests" && exit 1 - echo "${output}" | grep "x-local-rate-limit: true" && exit 1 -done - -run_log "Test upstream: localhost:${PORT_PROXY} with rate limit header three times" -for i in {1..3}; do - output=$(curl -s -X GET --head "http://localhost:${PORT_PROXY}") - echo "${output}" | grep "429 Too Many Requests" || exit 1 - echo "${output}" | grep "x-local-rate-limit: true" || exit 1 -done - -run_log "Test upstream: localhost:${PORT_PROXY} without rate limit response two times" -wait_for 5 responds_without_rate_limit 2 "http://localhost:${PORT_PROXY}" - -run_log "Test upstream: localhost:${PORT_PROXY} with rate limit response three times" -responds_with_rate_limit 3 "http://localhost:${PORT_PROXY}" - -run_log "Test admin interface: localhost:${PORT_STATS0}/stats/prometheus without rate limit header five times" -for i in {1..5}; do - output=$(curl -s -X GET --head "http://localhost:${PORT_STATS0}/stats/prometheus") - echo "${output}" | grep "429 Too Many Requests" && exit 1 - echo "${output}" | grep "x-local-rate-limit: true" && exit 1 -done - -run_log "Test admin interface: localhost:${PORT_STATS0}/stats/prometheus without rate limit response five times" -responds_without_rate_limit 5 "http://localhost:${PORT_STATS0}/stats/prometheus" - -run_log "Test admin interface: localhost:${PORT_STATS1}/stats/prometheus without rate limit header two times" -for i in {1..2}; do - output=$(curl -s -X GET --head "http://localhost:${PORT_STATS1}/stats/prometheus") - echo "${output}" | grep "429 Too Many Requests" && exit 1 - echo "${output}" | grep "x-local-rate-limit: true" && exit 1 -done - -run_log "Test admin interface: localhost:${PORT_STATS1}/stats/prometheus with rate limit header three times" -for i in {1..3}; do - output=$(curl -s -X GET --head "http://localhost:${PORT_STATS1}/stats/prometheus") - echo "${output}" | grep "429 Too Many Requests" || exit 1 - echo "${output}" | grep "x-local-rate-limit: true" || exit 1 -done - -run_log "Test admin interface: localhost:${PORT_STATS1}/stats/prometheus without rate limit response two times" -wait_for 5 responds_without_rate_limit 2 "http://localhost:${PORT_STATS1}/stats/prometheus" - -run_log "Test admin interface: localhost:${PORT_STATS1}/stats/prometheus with rate limit response three times" -responds_with_rate_limit 3 "http://localhost:${PORT_STATS1}/stats/prometheus" diff --git a/examples/locality-load-balancing/client.py b/examples/locality-load-balancing/client.py deleted file mode 100644 index 0eef5ff4dda4..000000000000 --- a/examples/locality-load-balancing/client.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import urllib.request -from collections import Counter - -url, n_requests = sys.argv[1], int(sys.argv[2]) - -count = Counter() -count_fail = 0 - -for i in range(n_requests): - try: - with urllib.request.urlopen(url) as resp: - content = resp.read().decode("utf-8").strip() - count[content] += 1 - except: - count_fail += 1 - -for k in count: - print(f"{k}: actual weight {count[k] / n_requests * 100}%") -print(f"Failed: {count_fail}") diff --git a/examples/locality-load-balancing/docker-compose.yaml b/examples/locality-load-balancing/docker-compose.yaml deleted file mode 100644 index 7366425bc8e5..000000000000 --- a/examples/locality-load-balancing/docker-compose.yaml +++ /dev/null @@ -1,52 +0,0 @@ -services: - - client-envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-load-balancing - depends_on: - backend-local-1: - condition: service_healthy - backend-local-2: - condition: service_healthy - backend-remote-1: - condition: service_healthy - backend-remote-2: - condition: service_healthy - - backend-local-1: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - environment: - - HOST=backend-local-1 - - backend-local-2: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - environment: - - HOST=backend-local-2 - - backend-remote-1: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - environment: - - HOST=backend-remote-1 - - backend-remote-2: - build: - context: ../shared/python - target: aiohttp-service - volumes: - - ./service.py:/code/service.py - environment: - - HOST=backend-remote-2 diff --git a/examples/locality-load-balancing/envoy.yaml b/examples/locality-load-balancing/envoy.yaml deleted file mode 100644 index be155f9bef53..000000000000 --- a/examples/locality-load-balancing/envoy.yaml +++ /dev/null @@ -1,108 +0,0 @@ -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 -static_resources: - listeners: - - name: backend - address: - socket_address: - address: 0.0.0.0 - port_value: 3000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: backend - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: backend - type: STRICT_DNS - lb_policy: ROUND_ROBIN - common_lb_config: - locality_weighted_lb_config: {} - health_checks: - - interval: 2s - timeout: 3s - no_traffic_interval: 4s - no_traffic_healthy_interval: 4s - unhealthy_threshold: 1 - healthy_threshold: 1 - http_health_check: - path: "/" - load_assignment: - cluster_name: backend - endpoints: - - locality: - region: local - zone: zone-1 - load_balancing_weight: 1 - priority: 0 # highest - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend-local-1 - port_value: 8080 - health_check_config: - port_value: 8080 - hostname: backend-local-1 - - locality: - region: local - zone: zone-2 - load_balancing_weight: 1 - priority: 1 - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend-local-2 - port_value: 8080 - health_check_config: - port_value: 8080 - hostname: backend-local-2 - - locality: - region: remote - zone: zone-1 - load_balancing_weight: 1 - priority: 1 - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend-remote-1 - port_value: 8080 - health_check_config: - port_value: 8080 - hostname: backend-remote-1 - - locality: - region: remote - zone: zone-2 - load_balancing_weight: 1 - priority: 2 - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend-remote-2 - port_value: 8080 - health_check_config: - port_value: 8080 - hostname: backend-remote-2 diff --git a/examples/locality-load-balancing/example.rst b/examples/locality-load-balancing/example.rst deleted file mode 100644 index 369379cecb30..000000000000 --- a/examples/locality-load-balancing/example.rst +++ /dev/null @@ -1,160 +0,0 @@ -.. _install_sandboxes_locality_load_balancing: - -Locality Weighted Load Balancing -================================ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -This example demonstrates the :ref:`locality weighted load balancing ` feature in Envoy proxy. The demo simulates a scenario that a backend service resides in two local zones and one remote zone. - -The components used in this demo are as follows: - -- A client container: runs Envoy proxy -- Backend container in the same locality as the client, with priority set to 0, referred to as ``local-1``. -- Backend container in the same locality as the client, with priority set to 1, referred to as ``local-2``. -- Backend container in the the remote locality, with priority set to 1, referred to as ``remote-1``. -- Backend container in the the remote locality, with priority set to 2, referred to as ``remote-2``. - -The client Envoy proxy configures the 4 backend containers in the same Envoy cluster, so that Envoy handles load balancing to those backend servers. From here we can see, we have localities with 3 different priorities: - -- priority 0: ``local-1`` -- priority 1: ``local-2`` and ``remote-1`` -- priority 2: ``remote-2`` - -In Envoy, when the healthiness of a given locality drops below a threshold (71% by default), the next priority locality will start to share the request loads. The demo below will show this behavior. - -Step 1: Start all of our containers -*********************************** - -In terminal, move to the ``examples/locality_load_balancing`` directory. - -To build this sandbox example and start the example services, run the following commands: - -.. code-block:: console - - # Start demo - $ docker compose up --build -d - -The locality configuration is set in the client container via static Envoy configuration file. Please refer to the ``cluster`` section of the :download:`proxy configuration <_include/locality-load-balancing/envoy.yaml>` file. - -.. note:: - The ``locality_weighted_lb_config`` must be set in ``common_lb_config`` for the ``load_balancing_weight`` to be used. - -Step 2: Scenario with one replica in the highest priority locality -****************************************************************** - -In this scenario, each locality has 1 healthy replica running and all the requests should be sent to the locality with the highest priority (i.e. lowest integer set for priority - ``0``), which is ``local-1``. - -.. code-block:: console - - # all requests to local-1 - $ docker compose exec -T client-envoy python3 client.py http://localhost:3000/ 100 - Hello from backend-local-1!: 100, 100.0% - Failed: 0 - -If locality ``local-1`` becomes unhealthy (i.e. fails the Envoy health check), the requests should be load balanced among the subsequent priority localities, which are ``local-2`` and ``remote-1``. They both have priority 1. We then send 100 requests to the backend cluster, and check the responders. - -.. code-block:: console - - # bring down local-1 - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_1:8080/unhealthy - [backend-local-1] Set to unhealthy - - # local-2 and remote-1 localities split the traffic 50:50 - $ docker compose exec -T client-envoy python3 client.py http://localhost:3000/ 100 - Hello from backend-remote-1!: 51, 51.0% - Hello from backend-local-2!: 49, 49.0% - Failed: 0 - -Now if ``local-2`` becomes unhealthy also, priority 1 locality is only 50% healthy. Thus priority 2 locality starts to share the request load. Requests will be sent to both ``remote-1`` and ``remote-2``. - -.. code-block:: console - - # bring down local-2 - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-2_1:8080/unhealthy - - # remote-1 locality receive 100% of the traffic - $ docker compose exec -T client-envoy python3 client.py http://localhost:3000/ 100 - Hello from backend-remote-1!: actual weight 69.0% - Hello from backend-remote-2!: actual weight 31.0% - Failed: 0 - - -Step 3: Recover servers -*********************** - -Before moving on, we need to server local-1 and local-2 first. - -.. code-block:: console - - # recover local-1 and local-2 after the demo - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_1:8080/healthy - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-2_1:8080/healthy - - -Step 4: Scenario with multiple replicas in the highest priority locality -************************************************************************ - -To demonstrate how locality based load balancing works in multiple replicas setup, let's now scale up the ``local-1`` locality to 5 replicas. - -.. code-block:: console - - $ docker compose up --scale backend-local-1=5 -d - -We are going to show the scenario that ``local-1`` is just partially healthy. So let's bring down 4 of the replicas in ``local-1``. - -.. code-block:: console - - # bring down local-1 replicas - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_2:8080/unhealthy - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_3:8080/unhealthy - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_4:8080/unhealthy - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-1_5:8080/unhealthy - -Then we check the endpoints again: - -.. code-block:: console - - # check healthiness - $ docker compose exec -T client-envoy curl -s localhost:8001/clusters | grep health_flags - - backend::172.28.0.4:8080::health_flags::/failed_active_hc - backend::172.28.0.2:8080::health_flags::/failed_active_hc - backend::172.28.0.5:8080::health_flags::/failed_active_hc - backend::172.28.0.6:8080::health_flags::/failed_active_hc - backend::172.28.0.7:8080::health_flags::healthy - backend::172.28.0.8:8080::health_flags::healthy - backend::172.28.0.3:8080::health_flags::healthy - -We can confirm that 4 backend endpoints become unhealthy. - -Now we send the 100 requests again. - -.. code-block:: console - - # watch traffic change - $ docker compose exec -T client-envoy python3 client.py http://localhost:3000/ 100 - - Hello from backend-remote-1!: actual weight 37.0% - Hello from backend-local-2!: actual weight 36.0% - Hello from backend-local-1!: actual weight 27.0% - Failed: 0 - -As ``local-1`` does not have enough healthy workloads, requests are partially shared by secondary localities. - -If we bring down all the servers in priority 1 locality, it will make priority 1 locality 0% healthy. The traffic should split between priority 0 and priority 2 localities. - -.. code-block:: console - - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-local-2_1:8080/unhealthy - $ docker compose exec -T client-envoy curl -s locality-load-balancing_backend-remote-1_1:8080/unhealthy - $ docker compose exec -T client-envoy python3 client.py http://localhost:3000/ 100 - - Hello from backend-remote-2!: actual weight 77.0% - Hello from backend-local-1!: actual weight 23.0% - Failed: 0 diff --git a/examples/locality-load-balancing/service.py b/examples/locality-load-balancing/service.py deleted file mode 100644 index c36ac65d5c74..000000000000 --- a/examples/locality-load-balancing/service.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging -import os - -from aiohttp import web - -routes = web.RouteTableDef() -healthy = True - - -@routes.get("/") -async def get(request): - global healthy - if healthy: - return web.Response(text=f"Hello from {os.environ['HOST']}!\n") - else: - raise web.HTTPServiceUnavailable(reason="Unhealthy") - - -@routes.get("/healthy") -async def healthy(request): - global healthy - healthy = True - return web.Response(text=f"[{os.environ['HOST']}] Set to healthy\n", status=201) - - -@routes.get("/unhealthy") -async def unhealthy(request): - global healthy - healthy = False - return web.Response(text=f"[{os.environ['HOST']}] Set to unhealthy\n", status=201) - - -if __name__ == "__main__": - app = web.Application() - logging.basicConfig(level=logging.DEBUG) - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/locality-load-balancing/verify.sh b/examples/locality-load-balancing/verify.sh deleted file mode 100755 index 7f6727811257..000000000000 --- a/examples/locality-load-balancing/verify.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash -e - -export NAME=locality-load-balancing - - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -dump_clusters () { - "${DOCKER_COMPOSE[@]}" exec -T client-envoy curl -s "localhost:8001/clusters" -} - -check_health() { - local ip_address - ip_address="$(docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${NAME}-${1}")" - dump_clusters | grep "backend::${ip_address}:8080::health_flags::${2}" -} - -check_backend() { - output=$("${DOCKER_COMPOSE[@]}" exec -T client-envoy python3 client.py http://localhost:3000/ 100) - echo "$output" - for expected in "$@"; do - count=$(echo "$output" | grep -c "$expected" | xargs) - if [ "$count" -eq 0 ]; then - echo "Test fail: locality $expected is expected to be routed to." - return 1 - fi - done -} - -make_healthy() { - "${DOCKER_COMPOSE[@]}" exec -T client-envoy curl -s "${NAME}-${1}:8080/healthy" - wait_for 5 check_health "${1}" healthy -} - -make_unhealthy() { - "${DOCKER_COMPOSE[@]}" exec -T client-envoy curl -s "${NAME}-${1}:8080/unhealthy" - wait_for 5 check_health "${1}" /failed_active_hc -} - -run_log "Wait for backend clusters to become healthy." -wait_for 5 check_health backend-local-1-1 healthy -wait_for 5 check_health backend-local-2-1 healthy -wait_for 5 check_health backend-remote-1-1 healthy -wait_for 5 check_health backend-remote-2-1 healthy - -run_log "Dump configured Envoy clusters" -dump_clusters - -run_log "=== Demo setup -client -> backend-local-1 [priority: 0, weight: 1] - -> backend-local-2 [priority: 1, weight: 1] - -> backend-remote-1 [priority: 1, weight: 1] - -> backend-remote-2 [priority: 2, weight: 1] -" - -run_log "=== Scenario 1: one replica in the highest priority locality" - -run_log "Send requests to backend." -wait_for 5 check_health backend-local-1-1 healthy -check_backend backend-local-1 - -run_log "Bring down backend-local-1. Priority 0 locality is 0% healthy." -make_unhealthy backend-local-1-1 - -run_log "Send requests to backend." -check_backend backend-local-2 backend-remote-1 - -run_log "Bring down backend-local-2. Priority 1 locality is 50% healthy." -make_unhealthy backend-local-2-1 - -run_log "Traffic is load balanced goes to remote only." -check_backend backend-remote-1 backend-remote-2 - -run_log "=== Scenario 2: multiple replica in the highest priority locality" -run_log "Recover local-1 and local-2" -make_healthy backend-local-1-1 -make_healthy backend-local-2-1 - -run_log "Scale backend-local-1 to 5 replicas." -"${DOCKER_COMPOSE[@]}" -p "${NAME}" up --scale backend-local-1=5 -d --build -wait_for 5 check_health backend-local-1-2 healthy -wait_for 5 check_health backend-local-1-3 healthy -wait_for 5 check_health backend-local-1-4 healthy -wait_for 5 check_health backend-local-1-5 healthy - -run_log "Bring down 4 replicas in backend-local-1. Priority 0 locality is 20% healthy." -make_unhealthy backend-local-1-2 -make_unhealthy backend-local-1-3 -make_unhealthy backend-local-1-4 -make_unhealthy backend-local-1-5 - -run_log "Send requests to backend." -check_backend backend-local-1 backend-local-2 backend-remote-1 - -run_log "Bring down all endpoints of priority 1. Priority 1 locality is 0% healthy." -make_unhealthy backend-local-2-1 -make_unhealthy backend-remote-1-1 - -run_log "Send requests to backend." -check_backend backend-local-1 backend-remote-2 diff --git a/examples/lua-cluster-specifier/README.md b/examples/lua-cluster-specifier/README.md deleted file mode 100644 index 0a1cd344b9b1..000000000000 --- a/examples/lua-cluster-specifier/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/lua-cluster-specifier.html) diff --git a/examples/lua-cluster-specifier/docker-compose.yaml b/examples/lua-cluster-specifier/docker-compose.yaml deleted file mode 100644 index 8faf8df65a2c..000000000000 --- a/examples/lua-cluster-specifier/docker-compose.yaml +++ /dev/null @@ -1,8 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000" diff --git a/examples/lua-cluster-specifier/envoy.yaml b/examples/lua-cluster-specifier/envoy.yaml deleted file mode 100644 index 178ced586715..000000000000 --- a/examples/lua-cluster-specifier/envoy.yaml +++ /dev/null @@ -1,56 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - codec_type: AUTO - route_config: - name: example_route - virtual_hosts: - - name: example_hosts - domains: - - "*" - routes: - - match: - prefix: "/" - route: - inline_cluster_specifier_plugin: - extension: - name: envoy.router.cluster_specifier_plugin.lua - typed_config: - "@type": type.googleapis.com/envoy.extensions.router.cluster_specifiers.lua.v3.LuaConfig - source_code: - inline_string: | - function envoy_on_route(route_handle) - local header_value = route_handle:headers():get("header_key") - if header_value == "fake" then - return "fake_cluster" - end - return "example_cluster" - end - default_cluster: example_cluster - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: example_cluster - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: example_cluster_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: httpbin.org - port_value: 80 diff --git a/examples/lua-cluster-specifier/example.rst b/examples/lua-cluster-specifier/example.rst deleted file mode 100644 index f927333ad755..000000000000 --- a/examples/lua-cluster-specifier/example.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. _install_sandboxes_lua_cluster_specifier: - -Lua cluster specifier -===================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we show how the `Lua `_ cluster specifier can be used with the -Envoy proxy. - -The example Envoy proxy configuration includes a Lua cluster specifier plugin that contains a function: - -- ``envoy_on_route(route_handle)`` - -.. tip:: - - See the :ref:`Lua cluster configuration documentation ` for an overview and - documentation regarding the function. - -Step 1: Build the sandbox -************************* - -Change to the ``examples/lua-cluster-specifier`` directory, and bring up the composition. - -.. code-block:: console - - $ pwd - envoy/examples/lua-cluster-specifier - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - -------------------------------------------------------------------------------------------- - lua-cluster-specifier-proxy-1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:10000->10000/tcp - -Step 2: Send a request to the normal service -******************************************** - -The output from the ``curl`` command below should return 200, since the lua code select the normal service. - -.. code-block:: console - - $ curl -i localhost:10000/anything 2>&1 |grep 200 - HTTP/1.1 200 OK - -Step 3: Send a request to the fake service -****************************************** - -If you specify the request header ``header_key:fake``, curl will return a ``503`` response, as -the Lua code will select the fake service. - -.. code-block:: console - - $ curl -i localhost:8000/anything -H "header_key:fake" 2>&1 |grep 503 - HTTP/1.1 503 Service Unavailable - -.. seealso:: - - :ref:`Envoy Lua cluster specifier ` - Learn more about the Envoy Lua cluster specifier. - - `Lua `_ - The Lua programming language. diff --git a/examples/lua-cluster-specifier/verify.sh b/examples/lua-cluster-specifier/verify.sh deleted file mode 100755 index ec37d5b46d89..000000000000 --- a/examples/lua-cluster-specifier/verify.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -e - -export NAME=lua-cluster-specifier -export PORT_PROXY="${LUA_CLUSTER_PORT_PROXY:-12620}" -export PORT_WEB="${LUA_CLUSTER_PORT_WEB:-12621}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test Lua cluster specifier with normal cluster" -responds_with_header \ - "HTTP/1.1 200 OK" \ - "http://localhost:${PORT_PROXY}/" - -run_log "Test Lua cluster specifier with fake cluster" -responds_with_header \ - "HTTP/1.1 503 Service Unavailable" \ - "http://localhost:${PORT_PROXY}/" \ - -H 'header_key: fake' diff --git a/examples/lua/README.md b/examples/lua/README.md deleted file mode 100644 index 912bd3992749..000000000000 --- a/examples/lua/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/lua.html). diff --git a/examples/lua/docker-compose.yaml b/examples/lua/docker-compose.yaml deleted file mode 100644 index b503ac37193b..000000000000 --- a/examples/lua/docker-compose.yaml +++ /dev/null @@ -1,15 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-lua - ports: - - "${PORT_PROXY:-8000}:8000" - - web_service: - build: - context: ../shared/echo - ports: - - "${PORT_WEB:-8080}:8080" diff --git a/examples/lua/envoy.yaml b/examples/lua/envoy.yaml deleted file mode 100644 index 0a8bf2d98c81..000000000000 --- a/examples/lua/envoy.yaml +++ /dev/null @@ -1,68 +0,0 @@ -static_resources: - listeners: - - name: main - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - codec_type: AUTO - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: - - "*" - routes: - - match: - prefix: "/multiple/lua/scripts" - route: - cluster: web_service - typed_per_filter_config: - lua_filter_with_custom_name_1: - "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute - source_code: - inline_string: | - function envoy_on_response(response_handle) - response_handle:headers():add("header_key_1", "header_value_1") - end - - match: - prefix: "/" - route: - cluster: web_service - http_filters: - - name: lua_filter_with_custom_name_0 - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua - default_source_code: - inline_string: | - local mylibrary = require("lib.mylibrary") - - function envoy_on_request(request_handle) - request_handle:headers():add("foo", mylibrary.foobar()) - end - - name: lua_filter_with_custom_name_1 - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: web_service - type: STRICT_DNS # static - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: web_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: web_service - port_value: 8080 diff --git a/examples/lua/example.rst b/examples/lua/example.rst deleted file mode 100644 index 480f180916dc..000000000000 --- a/examples/lua/example.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _install_sandboxes_lua: - -Lua filter -========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we show how the `Lua `_ filter can be used with the Envoy -proxy. - -The example Envoy proxy configuration includes two Lua filters that contain two different functions: - -- ``envoy_on_request(request_handle)`` -- ``envoy_on_response(response_handle)`` - -:ref:`See here ` for an overview of Envoy's Lua filter and documentation -regarding these functions. - -Step 1: Build the sandbox -************************* - -Change to the ``examples/lua`` directory. - -.. code-block:: console - - $ pwd - envoy/examples/lua - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - -------------------------------------------------------------------------------------------- - lua_proxy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp - lua_web_service_1 node ./index.js Up 0.0.0.0:8080->80/tcp - -Step 2: Send a request to the service -************************************* - -The output from the ``curl`` command below should include the header added by the Lua filter. - -Terminal 1 - -.. code-block:: console - - $ curl -v localhost:8000 2>&1 | grep Foo - Foo: bar <-- This is added by the common Lua filter. --< - -Step 3: Using multiple Lua filters at the same time -********************************************************* - -Two Lua filters are configured in the example Envoy proxy configuration. But the second one can only work at a -specific route. - -The output from the ``curl`` command below should include the headers that added by multiple Lua filters. - -Terminal 1 - -.. code-block:: console - - curl -v localhost:8000/multiple/lua/scripts 2>&1 | grep header_key_1 - < header_key_1: header_value_1 <-- This is added by the second route-specific Lua filter. --< - -.. seealso:: - - :ref:`Envoy Lua filter ` - Learn more about the Envoy Lua filter. - - `Lua `_ - The Lua programming language. diff --git a/examples/lua/lib/mylibrary.lua b/examples/lua/lib/mylibrary.lua deleted file mode 100644 index 6b4ffed1b476..000000000000 --- a/examples/lua/lib/mylibrary.lua +++ /dev/null @@ -1,7 +0,0 @@ -M = {} - -function M.foobar() - return "bar" -end - -return M diff --git a/examples/lua/verify.sh b/examples/lua/verify.sh deleted file mode 100755 index 28a043f0feb5..000000000000 --- a/examples/lua/verify.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -export NAME=lua -export PORT_PROXY="${LUA_PORT_PROXY:-11230}" -export PORT_WEB="${LUA_PORT_WEB:-11231}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test common Lua script" -responds_with \ - "Foo: bar" \ - "http://localhost:${PORT_PROXY}" - -run_log "Test route-specific Lua script" -responds_with_header \ - "header_key_1: header_value_1" \ - "http://localhost:${PORT_PROXY}/multiple/lua/scripts" - -# TODO(phlax): Add some docs/tests for web service diff --git a/examples/mysql/Dockerfile-mysql b/examples/mysql/Dockerfile-mysql deleted file mode 100644 index 6f5dde2defe9..000000000000 --- a/examples/mysql/Dockerfile-mysql +++ /dev/null @@ -1 +0,0 @@ -FROM mysql:9.0.1@sha256:d8df069848906979fd7511db00dc22efeb0a33a990d87c3c6d3fcdafd6fc6123 diff --git a/examples/mysql/README.md b/examples/mysql/README.md deleted file mode 100644 index a6987ece4c85..000000000000 --- a/examples/mysql/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/mysql.html). diff --git a/examples/mysql/docker-compose.yaml b/examples/mysql/docker-compose.yaml deleted file mode 100644 index 891358dd3127..000000000000 --- a/examples/mysql/docker-compose.yaml +++ /dev/null @@ -1,20 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_VARIANT: contrib-dev - depends_on: - mysql: - condition: service_started - ports: - - "${PORT_ADMIN:-8001}:8001" - - mysql: - build: - context: . - dockerfile: Dockerfile-mysql - environment: - - MYSQL_ALLOW_EMPTY_PASSWORD=yes diff --git a/examples/mysql/envoy.yaml b/examples/mysql/envoy.yaml deleted file mode 100644 index 4760b2c3eaca..000000000000 --- a/examples/mysql/envoy.yaml +++ /dev/null @@ -1,37 +0,0 @@ -static_resources: - listeners: - - name: mysql_listener - address: - socket_address: - address: 0.0.0.0 - port_value: 1999 - filter_chains: - - filters: - - name: envoy.filters.network.mysql_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.mysql_proxy.v3.MySQLProxy - stat_prefix: egress_mysql - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - stat_prefix: mysql_tcp - cluster: mysql_cluster - - clusters: - - name: mysql_cluster - type: STRICT_DNS - load_assignment: - cluster_name: mysql_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: mysql - port_value: 3306 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/mysql/example.rst b/examples/mysql/example.rst deleted file mode 100644 index 859c54df9753..000000000000 --- a/examples/mysql/example.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. _install_sandboxes_mysql: - -MySQL filter -============ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we show how the :ref:`MySQL filter ` can be used with the Envoy proxy. - -The Envoy proxy configuration includes a MySQL filter that parses queries and collects MySQL-specific -metrics. - -.. note:: - The current implementation of the protocol filter was tested extensively with MySQL - v5.7. It may also work with other versions. This example uses the current latest version. - - -Step 1: Build the sandbox -************************* - -Change to the ``examples/mysql`` directory. - -Build and start the containers. - -.. code-block:: console - - $ pwd - envoy/examples/mysql - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ---------------------------------------------------------------------------------------------------- - mysql_mysql_1 docker-entrypoint.sh mysqld Up 3306/tcp - mysql_proxy_1 /docker-entrypoint.sh /bin Up 10000/tcp, 1999/tcp, 0.0.0.0:8001->8001/tcp - -Step 2: Issue commands using mysql -********************************** - -Use ``mysql`` to issue some commands and verify they are routed via Envoy. - -.. code-block:: console - - $ docker run --rm -it --network mysql_default mysql:5.7 mysql -h proxy -P 1999 -u root --skip-ssl - ... snip ... - - mysql> CREATE DATABASE test; - Query OK, 1 row affected (0.00 sec) - - mysql> USE test; - Database changed - mysql> CREATE TABLE test ( text VARCHAR(255) ); - Query OK, 0 rows affected (0.01 sec) - - mysql> SELECT COUNT(*) FROM test; - +----------+ - | COUNT(*) | - +----------+ - | 0 | - +----------+ - 1 row in set (0.01 sec) - - mysql> INSERT INTO test VALUES ('hello, world!'); - Query OK, 1 row affected (0.00 sec) - - mysql> SELECT COUNT(*) FROM test; - +----------+ - | COUNT(*) | - +----------+ - | 1 | - +----------+ - 1 row in set (0.00 sec) - - mysql> exit - Bye - -Step 3: Check egress stats -************************** - -Check egress stats were updated. - -.. code-block:: console - - $ curl -s "http://localhost:8001/stats?filter=egress_mysql" - mysql.egress_mysql.auth_switch_request: 0 - mysql.egress_mysql.decoder_errors: 0 - mysql.egress_mysql.login_attempts: 1 - mysql.egress_mysql.login_failures: 0 - mysql.egress_mysql.protocol_errors: 0 - mysql.egress_mysql.queries_parse_error: 2 - mysql.egress_mysql.queries_parsed: 7 - mysql.egress_mysql.sessions: 6 - mysql.egress_mysql.upgraded_to_ssl: 0 - - - -Step 4: Check TCP stats -*********************** - -Check TCP stats were updated. - -.. code-block:: console - - $ curl -s "http://localhost:8001/stats?filter=mysql_tcp" - tcp.mysql_tcp.downstream_cx_no_route: 0 - tcp.mysql_tcp.downstream_cx_rx_bytes_buffered: 0 - tcp.mysql_tcp.downstream_cx_rx_bytes_total: 446 - tcp.mysql_tcp.downstream_cx_total: 1 - tcp.mysql_tcp.downstream_cx_tx_bytes_buffered: 0 - tcp.mysql_tcp.downstream_cx_tx_bytes_total: 677 - tcp.mysql_tcp.downstream_flow_control_paused_reading_total: 0 - tcp.mysql_tcp.downstream_flow_control_resumed_reading_total: 0 - tcp.mysql_tcp.idle_timeout: 0 - tcp.mysql_tcp.max_downstream_connection_duration: 0 - tcp.mysql_tcp.upstream_flush_active: 0 - tcp.mysql_tcp.upstream_flush_total: 0 - - -.. seealso:: - - :ref:`Envoy MySQL filter ` - Learn more about using the Envoy MySQL filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - `MySQL `_ - The MySQL database. diff --git a/examples/mysql/verify.sh b/examples/mysql/verify.sh deleted file mode 100755 index 212d4e204465..000000000000 --- a/examples/mysql/verify.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -e - -export NAME=mysql -export PORT_ADMIN="${MYSQL_PORT_ADMIN:-11300}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -_mysql () { - local mysql_client - mysql_client=(docker run --rm --network mysql_default mysql:latest mysql -h proxy -P 1999 -u root) - - "${mysql_client[@]}" "${@}" -} - -export -f _mysql - -wait_for 40 bash -c "_mysql -e 'SHOW DATABASES;'" - -run_log "Create a mysql database" -_mysql -e "CREATE DATABASE test;" -_mysql -e "show databases;" | grep test - -run_log "Create a mysql table" -_mysql -e "USE test; CREATE TABLE test ( text VARCHAR(255) ); INSERT INTO test VALUES ('hello, world!');" -_mysql -e "SELECT COUNT(*) from test.test;" | grep 1 - -run_log "Check mysql egress stats" -responds_with \ - egress_mysql \ - "http://localhost:${PORT_ADMIN}/stats?filter=egress_mysql" - -run_log "Check mysql TCP stats" -responds_with \ - mysql_tcp \ - "http://localhost:${PORT_ADMIN}/stats?filter=mysql_tcp" diff --git a/examples/opentelemetry/Dockerfile-opentelemetry b/examples/opentelemetry/Dockerfile-opentelemetry deleted file mode 100644 index 432b0f151160..000000000000 --- a/examples/opentelemetry/Dockerfile-opentelemetry +++ /dev/null @@ -1,11 +0,0 @@ -FROM alpine:3.20@sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 AS otelc_curl -RUN apk --update add curl - -FROM otel/opentelemetry-collector:latest@sha256:56b275978745d866d4e8bcb15de9e51ef259b61210b87c387bfd336a30a69acb - -COPY --from=otelc_curl / / - -COPY ./otel-collector-config.yaml /etc/otel-collector-config.yaml -USER 0 -RUN chmod o+r /etc/otel-collector-config.yaml -USER nobody diff --git a/examples/opentelemetry/README.md b/examples/opentelemetry/README.md deleted file mode 100644 index b2d6c335a2a8..000000000000 --- a/examples/opentelemetry/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/opentelemetry) diff --git a/examples/opentelemetry/docker-compose.yaml b/examples/opentelemetry/docker-compose.yaml deleted file mode 100644 index 153da43ee9ba..000000000000 --- a/examples/opentelemetry/docker-compose.yaml +++ /dev/null @@ -1,71 +0,0 @@ -services: - - envoy-front-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-front-proxy.yaml - depends_on: - opentelemetry: - condition: service_healthy - envoy-1: - condition: service_started - envoy-2: - condition: service_started - ports: - - "${PORT_PROXY:-10000}:10000" - - envoy-1: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-1.yaml - depends_on: - opentelemetry: - condition: service_healthy - service-1: - condition: service_healthy - envoy-2: - condition: service_started - - envoy-2: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-2.yaml - depends_on: - opentelemetry: - condition: service_healthy - service-2: - condition: service_healthy - - service-1: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=1 - - service-2: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=2 - - opentelemetry: - build: - context: . - dockerfile: Dockerfile-opentelemetry - healthcheck: - test: ["CMD-SHELL", "curl -sf http://localhost:13133 || exit 1"] - interval: 1s - timeout: 120s - retries: 120 - start_period: 5s - command: ["--config=/etc/otel-collector-config.yaml"] - ports: - - "${PORT_UI:-55679}:55679" diff --git a/examples/opentelemetry/envoy-1.yaml b/examples/opentelemetry/envoy-1.yaml deleted file mode 100644 index 085bdc7d2ab1..000000000000 --- a/examples/opentelemetry/envoy-1.yaml +++ /dev/null @@ -1,128 +0,0 @@ -# This proxy listens on 2 ports: -# -# 10000 -> routes to `service-1` -# 10001 -> routes to `envoy-2` - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.opentelemetry - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig - grpc_service: - envoy_grpc: - cluster_name: opentelemetry_collector - timeout: 0.250s - service_name: envoy-1 - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: service1_route - virtual_hosts: - - name: service1 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster1 - decorator: - operation: routeToService1 - - address: - socket_address: - address: 0.0.0.0 - port_value: 10001 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.opentelemetry - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig - grpc_service: - envoy_grpc: - cluster_name: opentelemetry_collector - timeout: 0.250s - service_name: envoy-1 - codec_type: AUTO - stat_prefix: egress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: envoy2_route - virtual_hosts: - - name: envoy2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2 - - clusters: - - name: service_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-1 - port_value: 8080 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-2 - port_value: 10000 - - name: opentelemetry_collector - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: opentelemetry_collector - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: opentelemetry - port_value: 4317 diff --git a/examples/opentelemetry/envoy-2.yaml b/examples/opentelemetry/envoy-2.yaml deleted file mode 100644 index f2ff064439b8..000000000000 --- a/examples/opentelemetry/envoy-2.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# This proxy listens on port 10000 and routes all queries to `service-2`. - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.opentelemetry - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig - grpc_service: - envoy_grpc: - cluster_name: opentelemetry_collector - timeout: 0.250s - service_name: envoy-2 - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: service2_route - virtual_hosts: - - name: service2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster2 - decorator: - operation: routeToService2 - - clusters: - - name: service_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-2 - port_value: 8080 - - name: opentelemetry_collector - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: opentelemetry_collector - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: opentelemetry - port_value: 4317 diff --git a/examples/opentelemetry/envoy-front-proxy.yaml b/examples/opentelemetry/envoy-front-proxy.yaml deleted file mode 100644 index 3e4f2007c55f..000000000000 --- a/examples/opentelemetry/envoy-front-proxy.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# This proxy listens on port 10000, and routes the following paths: -# -# /trace/1 -> routes to `envoy-1` on port 10000 -# /trace/2 -> routes to `envoy-1` on port 10001 (for onward routing to `envoy-2`) - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - generate_request_id: true - tracing: - provider: - name: envoy.tracers.opentelemetry - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig - grpc_service: - envoy_grpc: - cluster_name: opentelemetry_collector - timeout: 0.250s - service_name: front-envoy - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: proxy_routes - virtual_hosts: - - name: proxy - domains: - - "*" - routes: - - match: - prefix: "/trace/1" - route: - cluster: envoy_cluster1 - decorator: - operation: routeToEnvoy1 - - match: - prefix: "/trace/2" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2ViaEnvoy1 - - clusters: - - name: envoy_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10000 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10001 - - name: opentelemetry_collector - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: opentelemetry_collector - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: opentelemetry - port_value: 4317 diff --git a/examples/opentelemetry/example.rst b/examples/opentelemetry/example.rst deleted file mode 100644 index afbf11c20bcd..000000000000 --- a/examples/opentelemetry/example.rst +++ /dev/null @@ -1,121 +0,0 @@ -.. _install_sandboxes_opentelemetry: - -OpenTelemetry tracing -===================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -The OpenTelemetry tracing sandbox demonstrates Envoy's :ref:`request tracing ` -capabilities using `OpenTelemetry `_ as the tracing provider. - -In this example, 2 backend services are provided: - -- ``service-1`` -- ``service-2`` - -3 Envoy proxies are also provided to route requests to them: - -- ``envoy-front-proxy`` (:download:`envoy-front-proxy.yaml <_include/opentelemetry/envoy-front-proxy.yaml>`) -- ``envoy-1`` (:download:`envoy-1.yaml <_include/opentelemetry/envoy-1.yaml>`) -- ``envoy-2`` (:download:`envoy-2.yaml <_include/opentelemetry/envoy-2.yaml>`) - -Of these services, only the Envoy ``front-proxy`` service is exposed outside of the -:download:`composition <_include/opentelemetry/docker-compose.yaml>`, on port ``10000``. - -For ``service-1``, requests are routed based on the request path ``trace/1``, as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> ``service-1`` - -For ``service-2``, requests are routed based on the request path ``trace/2`` as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> Envoy(``envoy-2``) -> ``service-2`` - -All Envoy proxies are configured to collect request traces, as can be seen in their configurations, -propagating the spans (parent/child/shared context) generated by the OpenTelemetry tracer to a OpenTelemetry cluster. - -Each span records the latency of upstream API calls as well as information -needed to correlate the span with other related spans (e.g., the trace ID). - -The OpenTelemetry collector provides a web UI for viewing the collected traces on port ``55679``. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/opentelemetry`` in the Envoy repository. - -To build this sandbox example, and start the example services run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/opentelemetry - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------------------- - opentelemetry_envoy-1_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - opentelemetry_envoy-2_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - opentelemetry_envoy-front-proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - opentelemetry_opentelemetry_1 /otelcol --config=/etc/ote ... Up (healthy) 4317/tcp, 55678/tcp, 0.0.0.0:55679->55679/tcp - opentelemetry_service-1_1 python3 /code/service.py Up (healthy) - opentelemetry_service-2_1 python3 /code/service.py Up (healthy) - -Step 2: Make a request to ``service-1`` -*************************************** - -Now send a request to ``service-1``, by calling http://localhost:10000/trace/1. - -This will be routed via 2 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` - -.. code-block:: console - - $ curl localhost:10000/trace/1 - Hello from behind Envoy (service 1)! - -Step 3: Make a request to ``service-2`` -*************************************** - -Now send a request to ``service-2``, by calling http://localhost:10000/trace/2. - -This will be routed via all 3 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` -- ``envoy-2`` - -.. code-block:: console - - $ curl localhost:10000/trace/2 - Hello from behind Envoy (service 2)! - -Step 4: View the traces in OpenTelemetry UI -******************************************* - -Point your browser to http://localhost:55679/debug/tracez. - -You should see the OpenTelemetry dashboard. - -.. image:: /start/sandboxes/_static/opentelemetry-ui.png - -In the ``Latency Samples`` of ``opentelemetry.proto.collector.trace.v1.TraceService/Export`` you can explore the traces by clicking any value of -``[>0s][>10µs][>100µs][>1ms][>10ms][>100ms][>1s][>10s][>1m40s]``. - -.. image:: /start/sandboxes/_static/opentelemetry-ui-traces.png - -.. seealso:: - - :ref:`Request tracing ` - Learn more about using Envoy's request tracing. - - `OpenTelemetry `_ - OpenTelemetry tracing website. diff --git a/examples/opentelemetry/otel-collector-config.yaml b/examples/opentelemetry/otel-collector-config.yaml deleted file mode 100755 index b0ac5b631aba..000000000000 --- a/examples/opentelemetry/otel-collector-config.yaml +++ /dev/null @@ -1,38 +0,0 @@ -extensions: - memory_ballast: - size_mib: 512 - zpages: - endpoint: 0.0.0.0:55679 - health_check: - -receivers: - otlp: - protocols: - grpc: - http: - -processors: - batch: - memory_limiter: - # 75% of maximum memory up to 4G - limit_mib: 1536 - # 25% of limit up to 2G - spike_limit_mib: 512 - check_interval: 5s - -exporters: - logging: - loglevel: debug - -service: - pipelines: - traces: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [logging] - metrics: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [logging] - - extensions: [memory_ballast, zpages, health_check] diff --git a/examples/opentelemetry/verify.sh b/examples/opentelemetry/verify.sh deleted file mode 100755 index 9387c3853165..000000000000 --- a/examples/opentelemetry/verify.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e - -export NAME=opentelemetry -export PORT_PROXY="${OPENTELEMETRY_PORT_PROXY:-12000}" -export PORT_UI="${OPENTELEMETRY_PORT_UI:-12001}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Make a request to service-1" -responds_with \ - "Hello from behind Envoy (service 1)!" \ - "http://localhost:${PORT_PROXY}/trace/1" - -run_log "Make a request to service-2" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/trace/2" - -run_log "View the traces in OpenTelemetry UI" -responds_with \ - "" \ - "http://localhost:${PORT_UI}/debug/tracez" diff --git a/examples/postgres/README.md b/examples/postgres/README.md deleted file mode 100644 index 346b020e98c8..000000000000 --- a/examples/postgres/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/postgres.html). diff --git a/examples/postgres/docker-compose.yaml b/examples/postgres/docker-compose.yaml deleted file mode 100644 index 5a9f026c0eba..000000000000 --- a/examples/postgres/docker-compose.yaml +++ /dev/null @@ -1,21 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_VARIANT: contrib-dev - ports: - - "${PORT_ADMIN:-8001}:8001" - - postgres: - build: - context: ../shared/postgres - environment: - # WARNING! Do not use it on production environments because this will - # allow anyone with access to the Postgres port to access your - # database without a password, even if POSTGRES_PASSWORD is set. - # See PostgreSQL documentation about "trust": - # https://www.postgresql.org/docs/current/auth-trust.html - POSTGRES_HOST_AUTH_METHOD: trust diff --git a/examples/postgres/envoy.yaml b/examples/postgres/envoy.yaml deleted file mode 100644 index bc3bbe7b373e..000000000000 --- a/examples/postgres/envoy.yaml +++ /dev/null @@ -1,37 +0,0 @@ -static_resources: - listeners: - - name: postgres_listener - address: - socket_address: - address: 0.0.0.0 - port_value: 1999 - filter_chains: - - filters: - - name: envoy.filters.network.postgres_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy - stat_prefix: egress_postgres - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - stat_prefix: postgres_tcp - cluster: postgres_cluster - - clusters: - - name: postgres_cluster - type: STRICT_DNS - load_assignment: - cluster_name: postgres_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: postgres - port_value: 5432 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/postgres/example.rst b/examples/postgres/example.rst deleted file mode 100644 index 2e3be045f2bc..000000000000 --- a/examples/postgres/example.rst +++ /dev/null @@ -1,148 +0,0 @@ -.. _install_sandboxes_postgres: - -PostgreSQL filter -================= - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -In this example, we show how the :ref:`PostgreSQL filter ` -can be used with the Envoy proxy. - -The Envoy proxy configuration includes a PostgreSQL filter that parses queries and collects Postgres-specific metrics. - - -Step 1: Build the sandbox -************************* - -Change to the ``examples/postgres`` directory. - -Build and start the containers. - -.. code-block:: console - - $ pwd - envoy/examples/postgres - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - -------------------------------------------------------------------------------------------------------- - postgres_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp - postgres_proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 1999/tcp, 0.0.0.0:8001->8001/tcp - -Step 2: Issue commands using psql -********************************* - -This example uses ``psql`` client inside a container to issue some commands and -verify they are routed via Envoy. Note that we should set the environment variable -``PGSSLMODE=disable`` to disable ``SSL`` because the current implementation of the -filter can't decode encrypted sessions. - -.. code-block:: console - - $ docker run --rm -it --network envoymesh -e PGSSLMODE=disable postgres:latest psql -U postgres -h proxy -p 1999 - ... snip ... - - postgres=# CREATE DATABASE testdb; - CREATE DATABASE - postgres=# \c testdb - You are now connected to database "testdb" as user "postgres". - testdb=# CREATE TABLE tbl ( f SERIAL PRIMARY KEY ); - CREATE TABLE - testdb=# INSERT INTO tbl VALUES (DEFAULT); - INSERT 0 1 - testdb=# SELECT * FROM tbl; - f - --- - 1 - (1 row) - - testdb=# UPDATE tbl SET f = 2 WHERE f = 1; - UPDATE 1 - testdb=# INSERT INTO tbl VALUES (DEFAULT); - ERROR: duplicate key value violates unique constraint "tbl_pkey" - DETAIL: Key (f)=(2) already exists. - testdb=# DELETE FROM tbl; - DELETE 1 - testdb=# INSERT INTO tbl VALUES (DEFAULT); - INSERT 0 1 - testdb=# \q - - -Step 3: Check egress stats -************************** - -Check egress stats were updated. - -.. code-block:: console - - $ curl -s http://localhost:8001/stats?filter=egress_postgres - postgres.egress_postgres.errors: 1 - postgres.egress_postgres.errors_error: 1 - postgres.egress_postgres.errors_fatal: 0 - postgres.egress_postgres.errors_panic: 0 - postgres.egress_postgres.errors_unknown: 0 - postgres.egress_postgres.messages: 42 - postgres.egress_postgres.messages_backend: 32 - postgres.egress_postgres.messages_frontend: 10 - postgres.egress_postgres.messages_unknown: 0 - postgres.egress_postgres.notices: 0 - postgres.egress_postgres.notices_debug: 0 - postgres.egress_postgres.notices_info: 0 - postgres.egress_postgres.notices_log: 0 - postgres.egress_postgres.notices_notice: 0 - postgres.egress_postgres.notices_unknown: 0 - postgres.egress_postgres.notices_warning: 0 - postgres.egress_postgres.sessions: 1 - postgres.egress_postgres.sessions_encrypted: 0 - postgres.egress_postgres.sessions_unencrypted: 1 - postgres.egress_postgres.statements: 7 - postgres.egress_postgres.statements_delete: 1 - postgres.egress_postgres.statements_insert: 2 - postgres.egress_postgres.statements_other: 2 - postgres.egress_postgres.statements_parse_error: 4 - postgres.egress_postgres.statements_parsed: 4 - postgres.egress_postgres.statements_select: 1 - postgres.egress_postgres.statements_update: 1 - postgres.egress_postgres.transactions: 7 - postgres.egress_postgres.transactions_commit: 7 - postgres.egress_postgres.transactions_rollback: 0 - - -Step 4: Check TCP stats -*********************** - -Check TCP stats were updated. - -.. code-block:: console - - $ curl -s http://localhost:8001/stats?filter=postgres_tcp - tcp.postgres_tcp.downstream_cx_no_route: 0 - tcp.postgres_tcp.downstream_cx_rx_bytes_buffered: 0 - tcp.postgres_tcp.downstream_cx_rx_bytes_total: 373 - tcp.postgres_tcp.downstream_cx_total: 1 - tcp.postgres_tcp.downstream_cx_tx_bytes_buffered: 0 - tcp.postgres_tcp.downstream_cx_tx_bytes_total: 728 - tcp.postgres_tcp.downstream_flow_control_paused_reading_total: 0 - tcp.postgres_tcp.downstream_flow_control_resumed_reading_total: 0 - tcp.postgres_tcp.idle_timeout: 0 - tcp.postgres_tcp.max_downstream_connection_duration: 0 - tcp.postgres_tcp.upstream_flush_active: 0 - tcp.postgres_tcp.upstream_flush_total: 0 - -.. seealso:: - - :ref:`Envoy PostgreSQL filter ` - Learn more about using the Envoy PostgreSQL filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - `PostgreSQL `_ - The PostgreSQL database. diff --git a/examples/postgres/verify.sh b/examples/postgres/verify.sh deleted file mode 100755 index 97f9d3262328..000000000000 --- a/examples/postgres/verify.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -e - -export NAME=postgres -export PORT_ADMIN="${POSTGRES_PORT_ADMIN:-11600}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -_psql () { - local postgres_client - postgres_client=(docker run -i --rm --network postgres_default -e "PGSSLMODE=disable" postgres:latest psql -U postgres -h proxy -p 1999) - "${postgres_client[@]}" "${@}" -} - -export -f _psql - -wait_for 40 bash -c "_psql -c '\l'" - -DBNAME=testdb - -run_log "Create a postgres database" -_psql -c "CREATE DATABASE ${DBNAME};" -_psql -c '\l' | grep ${DBNAME} - -run_log "Create a postgres table" -_psql -d ${DBNAME} -c 'CREATE TABLE tbl ( f SERIAL PRIMARY KEY );' - -run_log "Insert some data" -_psql -d ${DBNAME} -c 'INSERT INTO tbl VALUES (DEFAULT);' - -run_log "Checking inserted data" -_psql -d ${DBNAME} -c 'SELECT * FROM tbl;' | grep -E '1$' - -run_log "Updating data" -_psql -d ${DBNAME} -c 'UPDATE tbl SET f = 2 WHERE f = 1;' - -run_log "Raise an exception for duplicate key violation" -_psql -d ${DBNAME} -c 'INSERT INTO tbl VALUES (DEFAULT);' 2>&1 | grep -A1 'duplicate key value violates unique constraint' - -run_log "Change some more data" -_psql -d ${DBNAME} -c 'DELETE FROM tbl;' -_psql -d ${DBNAME} -c 'INSERT INTO tbl VALUES (DEFAULT);' - -run_log "Check postgres egress stats" -responds_with \ - egress_postgres \ - "http://localhost:${PORT_ADMIN}/stats?filter=egress_postgres" - -run_log "Check postgres TCP stats" -responds_with \ - postgres_tcp \ - "http://localhost:${PORT_ADMIN}/stats?filter=postgres_tcp" diff --git a/examples/rbac/README.md b/examples/rbac/README.md deleted file mode 100644 index 33fdf8037fe6..000000000000 --- a/examples/rbac/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/rbac.html). diff --git a/examples/rbac/docker-compose.yaml b/examples/rbac/docker-compose.yaml deleted file mode 100644 index 6b51b21c40f9..000000000000 --- a/examples/rbac/docker-compose.yaml +++ /dev/null @@ -1,12 +0,0 @@ -services: - envoy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_ADMIN:-10001}:10001" - - backend: - build: - context: ../shared/echo diff --git a/examples/rbac/envoy.yaml b/examples/rbac/envoy.yaml deleted file mode 100644 index 599e89a1b59c..000000000000 --- a/examples/rbac/envoy.yaml +++ /dev/null @@ -1,79 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: service - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: local_service - http_filters: - - name: envoy.filters.http.rbac - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC - matcher: - matcher_list: - matchers: - - predicate: - not_matcher: - single_predicate: - input: - name: envoy.matching.inputs.request_headers - typed_config: - "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput - header_name: referer - value_match: - safe_regex: - google_re2: {} - regex: https?://(www.)?envoyproxy.io/docs/envoy.* - on_match: - action: - name: action - typed_config: - "@type": type.googleapis.com/envoy.config.rbac.v3.Action - name: illegal-referer - action: DENY - on_no_match: - action: - name: action - typed_config: - "@type": type.googleapis.com/envoy.config.rbac.v3.Action - name: all-pass - action: ALLOW - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: local_service - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: backend - port_value: 8080 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 10001 diff --git a/examples/rbac/example.rst b/examples/rbac/example.rst deleted file mode 100644 index d8607a4a14a6..000000000000 --- a/examples/rbac/example.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. _install_sandboxes_rbac: - -Role Based Access Control (RBAC) - HTTP -======================================= - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -RBAC is used to check if the incoming request is authorized or not. - -Envoy supports 2 types for RBAC: - -- L4 connections via the :ref:`Role Based Access Control (RBAC) Network Filter ` -- HTTP requests via the :ref:`Role Based Access Control (RBAC) Filter ` - -This sandbox provides an example of RBAC of HTTP requests. - -In the example, requests should only be allowed if its ``Referer`` header -matches the regex pattern ``https?://(www.)?envoyproxy.io/docs/envoy.*``. - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/rbac`` directory and bring up the docker composition. - -.. code-block:: console - - $ pwd - envoy/examples/rbac - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------ - rbac_backend_1 gunicorn -b 0.0.0.0:80 htt ... Up 0.0.0.0:8080->80/tcp - rbac_envoy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:10001->10001/tcp - -Step 2: Denial of upstream service using RBAC -********************************************* - -The sandbox is configured to proxy port ``10000`` to the upstream service. - -As the request does not have the required header it is denied, and Envoy refuses the connection with an HTTP 403 return code and with the content ``RBAC: access denied``. - -Now, use ``curl`` to make a request for the upstream service. - -.. code-block:: console - - $ curl -si localhost:10000 - HTTP/1.1 403 Forbidden - content-length: 19 - content-type: text/plain - date: Thu, 28 Jul 2022 06:48:43 GMT - server: envoy - - RBAC: access denied - -Step 3: Authorization of upstream service using RBAC -**************************************************** - -Now, we can make another request with proper headers set. - -.. code-block:: console - - $ curl -si -H "Referer: https://www.envoyproxy.io/docs/envoy" localhost:10000 | grep 200 - HTTP/1.1 200 OK - -Step 4: Check stats via admin -***************************** - -The sandbox is configured with the ``10001`` port for Envoy admin. - -Checking the admin interface we should now see that the RBAC stats are updated, with one request denied and the other allowed - -.. code-block:: console - - $ curl -s "http://localhost:10001/stats?filter=rbac" - http.ingress_http.rbac.allowed: 1 - http.ingress_http.rbac.denied: 1 - http.ingress_http.rbac.shadow_allowed: 0 - http.ingress_http.rbac.shadow_denied: 0 - -.. seealso:: - - :ref:`Role Based Access Control ` - Learn more about using Envoy's ``RBAC`` filter. - - :ref:`RBAC Network Filter API ` - API and configuration reference for Envoy's ``RBAC`` network filter. - - :ref:`RBAC HTTP Filter API ` - API and configuration reference for Envoy's ``RBAC`` HTTP filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/rbac/verify.sh b/examples/rbac/verify.sh deleted file mode 100755 index 4ed8e1a79c65..000000000000 --- a/examples/rbac/verify.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -e - -export NAME=rbac -export PORT_PROXY="${RBAC_PORT_PROXY:-11810}" -export PORT_ADMIN="${RBAC_PORT_ADMIN:-11811}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test upstream with access denied response" -responds_with "RBAC: access denied" "http://localhost:${PORT_PROXY}" - -run_log "Test authorized upstream response" -responds_without "RBAC: access denied" "http://localhost:${PORT_PROXY}" -H "Referer: https://www.envoyproxy.io/docs/envoy" - -run_log "Check admin stats" -responds_with rbac "http://localhost:${PORT_ADMIN}/stats?fitler=rbac" diff --git a/examples/redis/Dockerfile-redis b/examples/redis/Dockerfile-redis deleted file mode 100644 index 5d19ee90a244..000000000000 --- a/examples/redis/Dockerfile-redis +++ /dev/null @@ -1 +0,0 @@ -FROM redis@sha256:e59c42a34bdb950f988a1578504c31ce981096e3a18b83db1808bd7a32302e7f diff --git a/examples/redis/README.md b/examples/redis/README.md deleted file mode 100644 index f4b8b8885953..000000000000 --- a/examples/redis/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/redis.html). diff --git a/examples/redis/docker-compose.yaml b/examples/redis/docker-compose.yaml deleted file mode 100644 index b1559e6c82bb..000000000000 --- a/examples/redis/docker-compose.yaml +++ /dev/null @@ -1,14 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-1999}:1999" - - "${PORT_ADMIN:-8001}:8001" - - redis: - build: - context: . - dockerfile: Dockerfile-redis diff --git a/examples/redis/envoy.yaml b/examples/redis/envoy.yaml deleted file mode 100644 index 79cfda734792..000000000000 --- a/examples/redis/envoy.yaml +++ /dev/null @@ -1,36 +0,0 @@ -static_resources: - listeners: - - name: redis_listener - address: - socket_address: - address: 0.0.0.0 - port_value: 1999 - filter_chains: - - filters: - - name: envoy.filters.network.redis_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy - stat_prefix: egress_redis - settings: - op_timeout: 5s - prefix_routes: - catch_all_route: - cluster: redis_cluster - clusters: - - name: redis_cluster - type: STRICT_DNS # static - lb_policy: MAGLEV - load_assignment: - cluster_name: redis_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: redis - port_value: 6379 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/redis/example.rst b/examples/redis/example.rst deleted file mode 100644 index e6aaf53032cc..000000000000 --- a/examples/redis/example.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. _install_sandboxes_redis_filter: - -Redis filter -============ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -In this example, we show how a :ref:`Redis filter ` can be used with the Envoy proxy. - -The Envoy proxy configuration includes a Redis filter that routes egress requests to redis server. - -.. note:: - The example uses a redis container as the client but you could use a local redis client instead. - -Step 1: Build the sandbox -************************* - -Change to the ``examples/redis`` directory. - -Build and start the containers. - -.. code-block:: console - - $ pwd - envoy/examples/redis - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------------------------------ - redis_proxy_1 /docker-entrypoint.sh /bin Up 10000/tcp, 0.0.0.0:1999->1999/tcp, 0.0.0.0:8001->8001/tcp - redis_redis_1 docker-entrypoint.sh redis Up 6379/tcp - -Step 2: Issue Redis commands -**************************** - -Issue Redis commands using your favourite Redis client, such as ``redis-cli``, and verify they are routed via Envoy. - -.. code-block:: console - - $ docker run --rm --network host redis:latest redis-cli -h localhost -p 1999 set foo foo - OK - $ docker run --rm --network host redis:latest redis-cli -h localhost -p 1999 set bar bar - OK - $ docker run --rm --network host redis:latest redis-cli -h localhost -p 1999 get foo - "foo" - $ docker run --rm --network host redis:latest redis-cli -h localhost -p 1999 get bar - "bar" - -Step 3: Verify egress stats -*************************** - -Go to ``http://localhost:8001/stats?usedonly&filter=redis.egress_redis.command`` and verify the following stats: - -.. code-block:: none - - redis.egress_redis.command.get.total: 2 - redis.egress_redis.command.set.total: 2 - -.. seealso:: - - :ref:`Envoy Redis filter ` - Learn more about using the Envoy Redis filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - `Redis `_ - The Redis in-memory data structure store. diff --git a/examples/redis/verify.sh b/examples/redis/verify.sh deleted file mode 100755 index 005937a0339d..000000000000 --- a/examples/redis/verify.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -e - -export NAME=redis -export PORT_PROXY="${REDIS_PORT:-11800}" -export PORT_ADMIN="${REDIS_PORT_ADMIN:-11801}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -_redis_cli () { - local redis_client - redis_client=(docker run --rm --network host redis:latest redis-cli) - "${redis_client[@]}" "${@}" -} - -export -f _redis_cli - -wait_for 40 bash -c "_redis_cli -h localhost -p ${PORT_PROXY} set baz BAZ | grep OK" - -run_log "Test set" -_redis_cli -h localhost -p "${PORT_PROXY}" set foo FOO | grep OK -_redis_cli -h localhost -p "${PORT_PROXY}" set bar BAR | grep OK - -run_log "Test get" -_redis_cli -h localhost -p "${PORT_PROXY}" get foo | grep FOO -_redis_cli -h localhost -p "${PORT_PROXY}" get bar | grep BAR - -run_log "Test redis stats" -responds_with \ - egress_redis \ - "http://localhost:${PORT_ADMIN}/stats?usedonly&filter=redis.egress_redis.command" diff --git a/examples/route-mirror/README.md b/examples/route-mirror/README.md deleted file mode 100644 index 899406a73f16..000000000000 --- a/examples/route-mirror/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/route-mirror.html) diff --git a/examples/route-mirror/docker-compose.yaml b/examples/route-mirror/docker-compose.yaml deleted file mode 100644 index a002e4d2ec08..000000000000 --- a/examples/route-mirror/docker-compose.yaml +++ /dev/null @@ -1,45 +0,0 @@ -services: - - envoy-front-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000" - depends_on: - service1: - condition: service_healthy - service1-mirror: - condition: service_healthy - service2: - condition: service_healthy - service2-mirror: - condition: service_healthy - - service1: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=1 - - service1-mirror: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=1 - - service2: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=2 - - service2-mirror: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=2 diff --git a/examples/route-mirror/envoy.yaml b/examples/route-mirror/envoy.yaml deleted file mode 100644 index 200dd4dadf67..000000000000 --- a/examples/route-mirror/envoy.yaml +++ /dev/null @@ -1,90 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1 - request_mirror_policies: - - cluster: "service1-mirror" - - match: - prefix: "/service/2" - route: - cluster: service2 - request_mirror_policies: - - cluster_header: "x-mirror-cluster" - - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8080 - - - name: service1-mirror - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1-mirror - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1-mirror - port_value: 8080 - - - name: service2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2 - port_value: 8080 - - - name: service2-mirror - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2-mirror - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2-mirror - port_value: 8080 diff --git a/examples/route-mirror/example.rst b/examples/route-mirror/example.rst deleted file mode 100644 index 795bbf1b8c12..000000000000 --- a/examples/route-mirror/example.rst +++ /dev/null @@ -1,188 +0,0 @@ -.. _install_sandboxes_route_mirror: - -Route mirroring policies -======================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - -This simple example demonstrates Envoy's request mirroring capability using -`request mirror policies `__. - -Incoming requests are received by ``envoy-front-proxy`` service. - -Requests for the path ``/service/1`` are statically mirrored. - -Each request is handled by the ``service1`` cluster, and in addition, forwarded to -the ``service1-mirror`` cluster: - -.. literalinclude:: _include/route-mirror/envoy.yaml - :language: yaml - :lines: 16-34 - :linenos: - :emphasize-lines: 6-11 - :caption: Envoy configuration with static route mirror policy :download:`envoy.yaml <_include/route-mirror/envoy.yaml>` - -Requests for the path ``/service/2`` are dynamically mirrored according to the presence and value of -the ``x-mirror-cluster`` header. - -All reqests for this path are forwarded to the ``service2`` cluster, and are also mirrored -to the cluster named in the header. - -For example, if we send a request with the header ``x-mirror-cluster: service2-mirror``, -the request will be forwarded to the ``service2-mirror`` cluster. - -.. literalinclude:: _include/route-mirror/envoy.yaml - :language: yaml - :lines: 16-34 - :linenos: - :emphasize-lines: 12-17 - :caption: Envoy configuration with header based route mirror policy :download:`envoy.yaml <_include/route-mirror/envoy.yaml>` - - -.. warning:: - - Allowing a request header to determine the cluster that the request is mirrored to is most useful in - a trusted environment. - - For example, a downstream Envoy instance (or other application acting as a proxy) might - automatically add this header to requests for processing by an upstream Envoy instance - configured with request mirror policies. - - If you allow dynamic mirroring according to request header, you may wish to restrict which requests - can set or proxy the header. - -.. note:: - - Envoy will only return the response it receives from the primary cluster to the client. - - For this example, responses from ``service1`` and ``service2`` clusters will be sent - to the client. A response returned by the ``service1-mirror`` or the ``service2-mirror`` - cluster is not sent back to the client. - - This also means that any problems or latency in request processing in the mirror cluster - don't affect the response received by the client. - -Step 1: Build the sandbox -************************* - -Change to the ``examples/route-mirror`` directory. - -.. code-block:: console - - $ pwd - envoy/examples/route-mirror - $ docker compose build - $ docker compose up -d - $ docker compose ps - NAME COMMAND SERVICE STATUS PORTS - route-mirror-envoy-front-proxy-1 "/docker-entrypoint.…" envoy-front-proxy running 0.0.0.0:10000->10000/tcp, :::10000->10000/tcp - route-mirror-service1-1 "python3 /code/servi…" service1 running (healthy) - route-mirror-service1-mirror-1 "python3 /code/servi…" service1-mirror running (healthy) - route-mirror-service2-1 "python3 /code/servi…" service2 running (healthy) - route-mirror-service2-mirror-1 "python3 /code/servi…" service2-mirror running (healthy) - -Step 2: Make a request to the statically mirrored route -******************************************************* - -Let's send a request to the ``envoy-front-proxy`` service which forwards the request to -``service1`` and also sends the request to the service 1 mirror, ``service1-mirror``. - -.. code-block:: console - - $ curl localhost:10000/service/1 - Hello from behind Envoy (service 1)! - -Step 3: View logs for the statically mirrored request -***************************************************** - -The logs from the ``service1`` and ``service1-mirror`` services show that -both the ``service1`` and ``service1-mirror`` services received the request made -in Step 2. - -You can also see that for the request to the ``service1-mirror`` -service, the ``Host`` header was modified by Envoy to have a ``-shadow`` suffix -in the hostname. - -.. code-block:: console - - $ docker compose logs service1 - ... - Host: localhost:10000 - 192.168.80.6 - - [06/Oct/2022 03:56:22] "GET /service/1 HTTP/1.1" 200 - - - $ docker compose logs service1-mirror - ... - Host: localhost-shadow:10000 - 192.168.80.6 - - [06/Oct/2022 03:56:22] "GET /service/1 HTTP/1.1" 200 - - - -Step 4: Make a request to the route mirrored by request header -************************************************************** - -In this step, we will see a demonstration where the request specifies via a header, ``x-mirror-cluster``, -the cluster that envoy will mirror the request to. - -Let's send a request to the ``envoy-front-proxy`` service which forwards the request to -``service2`` and also mirrors the request to the cluster named, ``service2-mirror``. - -.. code-block:: console - - $ curl --header "x-mirror-cluster: service2-mirror" localhost:10000/service/2 - Hello from behind Envoy (service 2)! - - -Step 5: View logs for the request mirrored by request header -************************************************************ - -The logs show that both the ``service2`` and ``service2-mirror`` services -got the request. - -.. code-block:: console - - $ docker compose logs service2 - ... - Host: localhost:10000 - 192.168.80.6 - - [06/Oct/2022 03:56:22] "GET /service/2 HTTP/1.1" 200 - - - $ docker compose logs service2-mirror - ... - Host: localhost-shadow:10000 - 192.168.80.6 - - [06/Oct/2022 03:56:22] "GET /service/2 HTTP/1.1" 200 - - -You can also see that for the request to the ``service2-mirror`` service, the -``Host`` header was modified by Envoy to have a ``-shadow`` suffix in the -hostname. - -Step 6: Missing or invalid cluster name in request header -********************************************************* - -If you do not specify the ``x-mirror-cluster`` in the request to ``service2``, -or specify an unknown cluster, the request will not be mirrored but will be -handled in the normal way. - -.. code-block:: console - - $ curl localhost:10000/service/2 - Hello from behind Envoy (service 2)! - - $ curl --header "x-mirror-cluster: service2-mirror-non-existent" localhost:10000/service/2 - Hello from behind Envoy (service 2)! - -View the logs for ``service2`` and ``service2-mirror`` services. - -.. code-block:: console - - $ docker compose logs service2 - ... - Host: localhost:10000 - 192.168.80.6 - - [06/Oct/2022 03:56:22] "GET /service/2 HTTP/1.1" 200 - - - $ docker compose logs service2-mirror - # No new logs - -.. seealso:: - - :ref:`Envoy request mirror policy ` - Learn more Envoy's request mirroring policy. diff --git a/examples/route-mirror/verify.sh b/examples/route-mirror/verify.sh deleted file mode 100755 index e7a17bab07c0..000000000000 --- a/examples/route-mirror/verify.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -e - -export NAME=route-mirroring -export PORT_PROXY="${FRONT_PROXY_PORT_PROXY:-11820}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Make a request to the statically mirrored route" -responds_with "Hello from behind Envoy (service 1)!" "http://localhost:${PORT_PROXY}/service/1" - -run_log "View logs for the request mirrored by request header" -"${DOCKER_COMPOSE[@]}" logs service1 | grep --quiet "Host: localhost:${PORT_PROXY}" -"${DOCKER_COMPOSE[@]}" logs service1-mirror | grep --quiet "Host: localhost-shadow:${PORT_PROXY}" -"${DOCKER_COMPOSE[@]}" logs service1-mirror | grep --quiet GET - -run_log "Make a request to the route mirrored by request header" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/service/2" \ - --header 'x-mirror-cluster: service2-mirror' - -run_log "View logs for the request mirrored by request header" -"${DOCKER_COMPOSE[@]}" logs service2 | grep --quiet "Host: localhost:${PORT_PROXY}" -"${DOCKER_COMPOSE[@]}" logs service2-mirror | grep --quiet "Host: localhost-shadow:${PORT_PROXY}" -"${DOCKER_COMPOSE[@]}" logs service2-mirror | grep --quiet GET - -run_log "Missing or invalid cluster name in request header" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/service/2" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/service/2" \ - --header 'x-mirror-cluster: service2-mirror-non-existent' -"${DOCKER_COMPOSE[@]}" logs service2-mirror | grep -c GET | grep --quiet 1 diff --git a/examples/shared/build/Dockerfile b/examples/shared/build/Dockerfile deleted file mode 100644 index 92ea0ad5f146..000000000000 --- a/examples/shared/build/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM envoyproxy/envoy-build-ubuntu:f94a38f62220a2b017878b790b6ea98a0f6c5f9c@sha256:2dd96b6f43c08ccabd5f4747fce5854f5f96af509b32e5cf6493f136e9833649 -ENV DEBIAN_FRONTEND=noninteractive -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq install --no-install-recommends -y gosu \ - && groupadd -f envoygroup \ - && useradd -g envoygroup -m -d /home/envoybuild envoybuild diff --git a/examples/shared/build/build-entrypoint.sh b/examples/shared/build/build-entrypoint.sh deleted file mode 100755 index 7b824337aab6..000000000000 --- a/examples/shared/build/build-entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -e - -if [[ $(id -u envoybuild) != "${BUILD_UID}" ]]; then - usermod -u "${BUILD_UID}" envoybuild - chown envoybuild /home/envoybuild -fi - -chown envoybuild /output -chmod 1777 /tmp - -exec gosu envoybuild "$@" diff --git a/examples/shared/echo/Dockerfile b/examples/shared/echo/Dockerfile deleted file mode 100644 index 16d356efc745..000000000000 --- a/examples/shared/echo/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM jmalloc/echo-server@sha256:86f2c45aa7e7ebe1be30b21f8cfff25a7ed6e3b059751822d4b35bf244a688d5 diff --git a/examples/shared/echo2/Dockerfile b/examples/shared/echo2/Dockerfile deleted file mode 100644 index 48a273ba75d2..000000000000 --- a/examples/shared/echo2/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM mendhak/http-https-echo@sha256:a5661adca985057c94e31d633ee57051dbf29ada1ccfaa4f5fb58f4a5b1a2b2b diff --git a/examples/shared/envoy/Dockerfile b/examples/shared/envoy/Dockerfile deleted file mode 100644 index 2c7e17f67853..000000000000 --- a/examples/shared/envoy/Dockerfile +++ /dev/null @@ -1,96 +0,0 @@ -ARG ENVOY_IMAGE="${ENVOY_IMAGE:-envoyproxy/envoy}" -ARG ENVOY_VARIANT="${ENVOY_VARIANT:-dev}" - - -FROM ${ENVOY_IMAGE}:${ENVOY_VARIANT} AS envoy-base -ARG ENVOY_CONFIG=envoy.yaml -ENV ENVOY_CONFIG="$ENVOY_CONFIG" -ENV DEBIAN_FRONTEND=noninteractive -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - rm -f /etc/apt/apt.conf.d/docker-clean \ - && echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' | tee /etc/apt/apt.conf.d/keep-cache \ - && apt-get -qq update -y \ - && apt-get -qq install --no-install-recommends -y curl -COPY --chmod=777 "$ENVOY_CONFIG" /etc/envoy.yaml -CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml"] - -FROM envoy-base AS envoy-admin -ARG ENVOY_ADMIN_PORT=10001 -ENV ENVOY_ADMIN_PORT="$ENVOY_ADMIN_PORT" -HEALTHCHECK \ - --interval=1s \ - --timeout=1s \ - --start-period=1s \ - --retries=3 \ - CMD curl -s "localhost:${ENVOY_ADMIN_PORT}/stats?filter=server.state" | grep 0 \ - && curl -s "localhost:${ENVOY_ADMIN_PORT}/stats?filter=listener_manager.workers_started" | grep 1 - -FROM envoy-base AS envoy-fault-injection -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update -y \ - && apt-get -qq install --no-install-recommends -y tree -COPY enable_delay_fault_injection.sh disable_delay_fault_injection.sh enable_abort_fault_injection.sh disable_abort_fault_injection.sh send_request.sh / - - -FROM envoy-base AS envoy-jaeger-native -# -# for discussion on jaeger binary compatibility, and the source of the file, see here: -# https://github.com/envoyproxy/envoy/issues/11382#issuecomment-638012072 -# -RUN echo "4a7d17d4724ee890490bcd6cfdedb12a02316a3d33214348d30979abd201f1ca /usr/local/lib/libjaegertracing_plugin.so" > /tmp/checksum \ - && curl -Ls https://github.com/envoyproxy/misc/releases/download/jaegertracing-plugin/jaegertracing-plugin-centos.tar.gz \ - | tar zxf - -C /usr/local/lib \ - && mv /usr/local/lib/libjaegertracing.so.0.4.2 /usr/local/lib/libjaegertracing_plugin.so \ - && sha256sum -c /tmp/checksum \ - && rm /tmp/checksum - - -FROM envoy-base AS envoy-load-balancing -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update -y \ - && apt-get -qq install --no-install-recommends -y python3 -COPY ./client.py /client.py -EXPOSE 8001 - - -FROM envoy-base AS envoy-double-proxy-base -COPY --chmod=777 ./certs/ca.crt /certs/cacert.pem - - -FROM envoy-double-proxy-base AS envoy-double-proxy-frontend -COPY --chmod=777 ./certs/postgres-frontend.example.com.crt /certs/clientcert.pem -COPY --chmod=777 ./certs/example.com.key /certs/clientkey.pem - - -FROM envoy-double-proxy-base AS envoy-double-proxy-backend -COPY --chmod=777 ./certs/postgres-backend.example.com.crt /certs/servercert.pem -COPY --chmod=777 ./certs/example.com.key /certs/serverkey.pem - - -FROM envoy-base AS envoy-certs -COPY --chmod=777 ./certs /certs - - -FROM envoy-base AS envoy-lua -ADD --chmod=777 ./lib/mylibrary.lua /lib/mylibrary.lua - - -FROM envoy-base AS envoy-go -ENV GODEBUG=cgocheck=0 -COPY --chmod=777 ./lib/simple.so /lib/simple.so - - -FROM envoy-base AS envoy-ext_authz -COPY --chmod=777 ./config /etc/envoy-config -COPY --chmod=777 ./run_envoy.sh /run_envoy.sh -CMD ["/bin/sh", "/run_envoy.sh"] - - -FROM envoy-base AS envoy-dynamic-fs -COPY --chmod=777 ./configs /var/lib/envoy - - -FROM envoy-base diff --git a/examples/shared/golang/Dockerfile b/examples/shared/golang/Dockerfile deleted file mode 100644 index b2d762cd2a17..000000000000 --- a/examples/shared/golang/Dockerfile +++ /dev/null @@ -1,77 +0,0 @@ -FROM debian:bookworm-slim@sha256:5f7d5664eae4a192c2d2d6cb67fc3f3c7891a8722cd2903cc35aa649a12b0c8d AS os-base -RUN rm -f /etc/apt/apt.conf.d/docker-clean \ - && echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' | tee /etc/apt/apt.conf.d/keep-cache - - -FROM golang:1.22.5-bookworm@sha256:af9b40f2b1851be993763b85288f8434af87b5678af04355b1e33ff530b5765f AS golang-base - - -FROM golang-base AS golang-control-plane-builder -ARG GO_RESOURCE=resource.go -RUN git clone https://github.com/envoyproxy/go-control-plane && cd go-control-plane && git checkout b4adc3bb5fe5288bff01cd452dad418ef98c676e -ADD "$GO_RESOURCE" /go/go-control-plane/internal/example/resource.go -RUN cd go-control-plane && make bin/example -WORKDIR /go/go-control-plane - - -FROM os-base AS golang-control-plane -ENV DEBIAN_FRONTEND=noninteractive -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update \ - && apt-get -qq install --no-install-recommends -y netcat-traditional -COPY --from=golang-control-plane-builder /go/go-control-plane/bin/example /usr/local/bin/example - - -FROM golang-base AS golang-base-builder -ARG GO_APP=. -ARG GO_APP_NAME=grpc-service -RUN echo "COPY $GO_APP -> ${GO_APP_NAME} ..." -COPY "$GO_APP" /app - - -FROM golang-base-builder AS golang-grpc-auth-builder -RUN make -C "/app/${GO_APP_NAME}" - - -FROM os-base AS golang-grpc-auth -COPY --from=golang-grpc-auth-builder /app/grpc-service/server /app/server -CMD ["/app/server", "-users", "/etc/users.json"] - - -FROM golang-base AS golang-grpc-server-builder -WORKDIR /build -# Resolve and build Go dependencies as Docker cache -COPY go.mod /build/go.mod -COPY go.sum /build/go.sum -ENV GO111MODULE=on -RUN go mod download -COPY service.go /build/main.go -COPY kv/ /build/kv -# Build for linux -ENV GOOS=linux -ENV GOARCH=amd64 -ENV CGO_ENABLED=0 -RUN go build -o server - - -FROM os-base AS golang-grpc-server -WORKDIR /root/ -# Copy the linux amd64 binary -COPY --from=golang-grpc-server-builder /build/server /bin/ -ENTRYPOINT /bin/server - - -FROM golang-base AS golang-lrs-builder -COPY ./server /go/src/github.com/envoyproxy/envoy/example/load-reporting-service/server -COPY *.go /go/src/github.com/envoyproxy/envoy/example/load-reporting-service/ -COPY go.sum /go/src/github.com/envoyproxy/envoy/example/load-reporting-service -COPY go.mod /go/src/github.com/envoyproxy/envoy/example/load-reporting-service -WORKDIR /go/src/github.com/envoyproxy/envoy/example/load-reporting-service -RUN go mod download \ - && go install /go/src/github.com/envoyproxy/envoy/example/load-reporting-service - - -FROM os-base AS golang-lrs -COPY --from=golang-lrs-builder /go/bin/load-reporting-service /usr/local/bin/load-reporting-service -CMD ["load-reporting-service"] diff --git a/examples/shared/jaeger/Dockerfile b/examples/shared/jaeger/Dockerfile deleted file mode 100644 index dc05858f6d17..000000000000 --- a/examples/shared/jaeger/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM jaegertracing/all-in-one@sha256:dd79a8dcf45a48e85b419d19559f7448ad83ea6f4d631b8f361b52686b3e5f72 -HEALTHCHECK \ - --interval=1s \ - --timeout=1s \ - --start-period=1s \ - --retries=60 \ - CMD wget -q --header='Content-Type:application/json' -O - http://localhost:14269/health | grep "Server available" diff --git a/examples/shared/node/Dockerfile b/examples/shared/node/Dockerfile deleted file mode 100644 index afc7a67449ed..000000000000 --- a/examples/shared/node/Dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -FROM node:22.5-bookworm-slim@sha256:2fb92fe9d7350866a73c5cc311c1a19919ffd47e8592d4233374ee330e3bdb1e AS node-base - - -FROM node-base AS node-http-auth -ARG NODE_APP=. -ARG NODE_APP_NAME=http-service/server -# Add an env to save ARG -ENV NODE_APP_PATH "/app/${NODE_APP_NAME}" -COPY "$NODE_APP" /app -# Dont use exec form to interpolate correctly -CMD node $NODE_APP_PATH - - -FROM node-base AS yarn -ARG SERVICE_PORT=3000 -ENV DEBIAN_FRONTEND=noninteractive \ - SERVICE_PORT=$SERVICE_PORT -COPY --chmod=755 ./scripts/entrypoint.sh /entrypoint.sh -COPY --chmod=755 ./scripts/build.sh /usr/local/bin/build.sh -COPY --chmod=755 ./scripts/dev.sh /usr/local/bin/dev.sh -COPY --chmod=644 ./routes.jq /usr/local/share/routes.jq -RUN apt-get update \ - && apt-get -qq install -y --no-install-recommends gosu jq netcat-traditional yq -ENTRYPOINT ["/entrypoint.sh"] -CMD ["dev.sh"] -HEALTHCHECK \ - --interval=2s \ - --timeout=1s \ - --start-period=1s \ - --retries=30 \ - CMD nc -zv localhost "$SERVICE_PORT" - - -FROM yarn AS yarn-routed -COPY --chmod=755 ./scripts/build-routed.sh /usr/local/bin/build.sh diff --git a/examples/shared/node/routes.jq b/examples/shared/node/routes.jq deleted file mode 100644 index f5a61d71c558..000000000000 --- a/examples/shared/node/routes.jq +++ /dev/null @@ -1,49 +0,0 @@ -# Generate direct_response routes for a passed in file list -# Expects an xDS config to be passed as the `base` argument to -# inject the routes into. - -def getMimeType: - {".js": "text/javascript", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".png": "image/png", - ".gif": "image/gif", - ".svg": "image/svg+xml", - ".ico": "image/x-icon", - ".css": "text/css", - ".html": "text/html", - ".txt": "text/plain", - ".xml": "application/xml", - ".json": "application/json", - ".pdf": "application/pdf", - ".zip": "application/zip", - ".tar": "application/x-tar", - ".gz": "application/gzip" - }[match("\\.[^.]*$").string // "application/octet-stream"] -; - -def pathToDirectResponse: - . as $path - | sub("^dist/"; "/") as $asset - | $asset - | sub("^/index.html$"; "/") as $path - | if $path == "/" then - {prefix: $path} - else {$path} end - | {match: ., - direct_response: { - status: 200, - body: {filename: "/var/www/html\($asset)"} - }, - response_headers_to_add: [ - {header: { - key: "Content-Type", - value: ($asset | getMimeType)}}]} -; - -split("\n") as $assets -| ($base | fromjson) as $base -| $assets -| map(select(. != "") | pathToDirectResponse) as $routes -| $base -| .resources[0].filter_chains[0].filters[0].typed_config.route_config.virtual_hosts[0].routes = $routes diff --git a/examples/shared/node/scripts/build-routed.sh b/examples/shared/node/scripts/build-routed.sh deleted file mode 100755 index 875d97b7746a..000000000000 --- a/examples/shared/node/scripts/build-routed.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -yarn -yarn build - -BASE=$(yq -c < /var/lib/envoy/lds.tmpl.yml) -ASSETS=$(find dist -type f) -echo "$ASSETS" \ - | jq --arg base "$BASE" -Rs -f /usr/local/share/routes.jq \ - > /var/lib/envoy/lds.update.yml -mv -f /var/lib/envoy/lds.update.yml /var/lib/envoy/lds.yml diff --git a/examples/shared/node/scripts/build.sh b/examples/shared/node/scripts/build.sh deleted file mode 100644 index 4c3c1994bb0b..000000000000 --- a/examples/shared/node/scripts/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -yarn -yarn build diff --git a/examples/shared/node/scripts/dev.sh b/examples/shared/node/scripts/dev.sh deleted file mode 100755 index fdf461a027f5..000000000000 --- a/examples/shared/node/scripts/dev.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -yarn -yarn dev --host 0.0.0.0 --port 3000 diff --git a/examples/shared/node/scripts/entrypoint.sh b/examples/shared/node/scripts/entrypoint.sh deleted file mode 100755 index bea8c478a328..000000000000 --- a/examples/shared/node/scripts/entrypoint.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e - -# Add local user -# Either use the LOCAL_USER_ID if passed in at runtime or -# fallback - -DEFAULT_USER_NAME=node - -USER_UID=${LOCAL_UID:-1000} -USER_NAME=${LOCAL_USER_NAME:-worker} -USER_HOME=${LOCAL_USER_HOME:-"/home/${USER_NAME}"} - -echo "Starting (${*}) with user: $USER_UID $USER_NAME $USER_HOME" -usermod -l "$USER_NAME" -md "$USER_HOME" "$DEFAULT_USER_NAME" || : -chown "$USER_NAME" "$USER_HOME" -export HOME="${USER_HOME}" -export PATH=$PATH:"${HOME}/.yarn/bin/" -mkdir -p ./dist -chown -R "$USER_NAME" ./dist -exec /usr/sbin/gosu "${USER_NAME}" "$@" diff --git a/examples/shared/postgres/Dockerfile b/examples/shared/postgres/Dockerfile deleted file mode 100644 index b6355bb29481..000000000000 --- a/examples/shared/postgres/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM postgres:latest@sha256:d0f363f8366fbc3f52d172c6e76bc27151c3d643b870e1062b4e8bfe65baf609 -COPY docker-healthcheck.sh /usr/local/bin/ -HEALTHCHECK CMD ["docker-healthcheck.sh"] diff --git a/examples/shared/postgres/docker-healthcheck.sh b/examples/shared/postgres/docker-healthcheck.sh deleted file mode 100755 index ddb39f942c67..000000000000 --- a/examples/shared/postgres/docker-healthcheck.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# https://github.com/docker-library/healthcheck/tree/master/postgres - -set -eo pipefail - -host="$(hostname -i || echo '127.0.0.1')" -user="${POSTGRES_USER:-postgres}" -db="${POSTGRES_DB:-$POSTGRES_USER}" -export PGPASSWORD="${POSTGRES_PASSWORD:-}" - -args=( - # force postgres to not use the local unix socket (test "external" connectibility) - --host "$host" - --username "$user" - --dbname "$db" - --quiet --no-align --tuples-only -) - -if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then - exit 0 -fi - -exit 1 diff --git a/examples/shared/python/Dockerfile b/examples/shared/python/Dockerfile deleted file mode 100644 index 1ce69ebf8a6e..000000000000 --- a/examples/shared/python/Dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -FROM python:3.11.5-slim-bookworm@sha256:edaf703dce209d774af3ff768fc92b1e3b60261e7602126276f9ceb0e3a96874 AS python-base -RUN rm -f /etc/apt/apt.conf.d/docker-clean \ - && echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' | tee /etc/apt/apt.conf.d/keep-cache -ARG PYTHON_REQUIREMENTS_FILE=aiohttp/requirements.txt -ADD "$PYTHON_REQUIREMENTS_FILE" /tmp/requirements.txt - - -FROM python-base AS python-grpc-client -WORKDIR /client -RUN pip install --require-hashes -qr /tmp/requirements.txt -# Copy the sources, including the stubs -COPY --chmod=777 client.py /client/grpc-kv-client.py -COPY kv /client/kv -CMD tail -f /dev/null - - -FROM python-base AS aiohttp-service -ARG SERVICE_PORT=8080 -ENV DEBIAN_FRONTEND=noninteractive \ - SERVICE_PORT=$SERVICE_PORT -ADD "$PYTHON_REQUIREMENTS_FILE" /tmp/requirements.txt -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - pip3 install --require-hashes -qr /tmp/requirements.txt \ - && apt-get -qq update \ - && apt-get -qq install -y --no-install-recommends netcat-traditional \ - && mkdir /code -HEALTHCHECK \ - --interval=1s \ - --timeout=1s \ - --start-period=1s \ - --retries=3 \ - CMD nc -zv localhost "$SERVICE_PORT" -ENTRYPOINT ["python3", "/code/service.py"] - - -FROM aiohttp-service AS aiohttp-tracing-service -ADD tracing/service.py /code/service.py - - -FROM aiohttp-service AS aiohttp-tracing-service2 -ADD tracing/service2.py /code/service.py - - -FROM aiohttp-service AS aiohttp-tracing-service3 -COPY --from=envoyproxy/envoy:dev /usr/local/bin/envoy /usr/local/bin/envoy -COPY --chmod=777 tracing/start_service.sh /usr/local/bin/start_service.sh -ADD tracing/service2.py /code/service.py -ENTRYPOINT ["/usr/local/bin/start_service.sh"] - - -FROM aiohttp-tracing-service3 AS aiohttp-jaeger-service -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update \ - && apt-get -qq install --no-install-recommends -y curl -# -# for discussion on jaeger binary compatibility, and the source of the file, see here: -# https://github.com/envoyproxy/envoy/issues/11382#issuecomment-638012072 -# -RUN echo "4a7d17d4724ee890490bcd6cfdedb12a02316a3d33214348d30979abd201f1ca /usr/local/lib/libjaegertracing_plugin.so" > /tmp/checksum \ - && curl -Ls https://github.com/envoyproxy/misc/releases/download/jaegertracing-plugin/jaegertracing-plugin-centos.tar.gz \ - | tar zxf - -C /usr/local/lib \ - && mv /usr/local/lib/libjaegertracing.so.0.4.2 /usr/local/lib/libjaegertracing_plugin.so \ - && sha256sum -c /tmp/checksum \ - && rm /tmp/checksum - - -FROM aiohttp-service AS aiohttp-hello-service -ADD service.py /code/service.py - - -FROM aiohttp-service AS aiohttp-data-service -RUN mkdir -p /code/data -RUN dd if=/dev/zero of="/code/data/file.txt" bs=1024 count=10240 \ - && dd if=/dev/zero of="/code/data/file.json" bs=1024 count=10240 -ADD data-service.py /code/service.py - - -FROM aiohttp-service AS aiohttp-postgres-service -ADD postgres/requirements.txt /tmp/requirements.txt -RUN pip3 install -qr /tmp/requirements.txt diff --git a/examples/shared/python/aiohttp/requirements.in b/examples/shared/python/aiohttp/requirements.in deleted file mode 100644 index df84c65abf50..000000000000 --- a/examples/shared/python/aiohttp/requirements.in +++ /dev/null @@ -1,2 +0,0 @@ -aiohttp -pyyaml diff --git a/examples/shared/python/aiohttp/requirements.txt b/examples/shared/python/aiohttp/requirements.txt deleted file mode 100644 index 80f534780de7..000000000000 --- a/examples/shared/python/aiohttp/requirements.txt +++ /dev/null @@ -1,367 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -aiohttp==3.9.5 \ - --hash=sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8 \ - --hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \ - --hash=sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475 \ - --hash=sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed \ - --hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \ - --hash=sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372 \ - --hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \ - --hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \ - --hash=sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1 \ - --hash=sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd \ - --hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \ - --hash=sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb \ - --hash=sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46 \ - --hash=sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de \ - --hash=sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78 \ - --hash=sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c \ - --hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \ - --hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \ - --hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \ - --hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \ - --hash=sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156 \ - --hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \ - --hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \ - --hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \ - --hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \ - --hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \ - --hash=sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da \ - --hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \ - --hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \ - --hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \ - --hash=sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8 \ - --hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \ - --hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \ - --hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \ - --hash=sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09 \ - --hash=sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031 \ - --hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \ - --hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \ - --hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \ - --hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \ - --hash=sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe \ - --hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \ - --hash=sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2 \ - --hash=sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1 \ - --hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \ - --hash=sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b \ - --hash=sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b \ - --hash=sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106 \ - --hash=sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac \ - --hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \ - --hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \ - --hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \ - --hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \ - --hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \ - --hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \ - --hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \ - --hash=sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a \ - --hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \ - --hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \ - --hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \ - --hash=sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24 \ - --hash=sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed \ - --hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \ - --hash=sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e \ - --hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \ - --hash=sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a \ - --hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \ - --hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \ - --hash=sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2 \ - --hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \ - --hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \ - --hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \ - --hash=sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11 \ - --hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \ - --hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \ - --hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f - # via -r requirements.in -aiosignal==1.3.1 \ - --hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \ - --hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17 - # via aiohttp -attrs==23.1.0 \ - --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ - --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 - # via aiohttp -frozenlist==1.4.0 \ - --hash=sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6 \ - --hash=sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01 \ - --hash=sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251 \ - --hash=sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9 \ - --hash=sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b \ - --hash=sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87 \ - --hash=sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf \ - --hash=sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f \ - --hash=sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0 \ - --hash=sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2 \ - --hash=sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b \ - --hash=sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc \ - --hash=sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c \ - --hash=sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467 \ - --hash=sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9 \ - --hash=sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1 \ - --hash=sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a \ - --hash=sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79 \ - --hash=sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167 \ - --hash=sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300 \ - --hash=sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf \ - --hash=sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea \ - --hash=sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2 \ - --hash=sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab \ - --hash=sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3 \ - --hash=sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb \ - --hash=sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087 \ - --hash=sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc \ - --hash=sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8 \ - --hash=sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62 \ - --hash=sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f \ - --hash=sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326 \ - --hash=sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c \ - --hash=sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431 \ - --hash=sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963 \ - --hash=sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7 \ - --hash=sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef \ - --hash=sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3 \ - --hash=sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956 \ - --hash=sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781 \ - --hash=sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472 \ - --hash=sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc \ - --hash=sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839 \ - --hash=sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672 \ - --hash=sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3 \ - --hash=sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503 \ - --hash=sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d \ - --hash=sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8 \ - --hash=sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b \ - --hash=sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc \ - --hash=sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f \ - --hash=sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559 \ - --hash=sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b \ - --hash=sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95 \ - --hash=sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb \ - --hash=sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963 \ - --hash=sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919 \ - --hash=sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f \ - --hash=sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3 \ - --hash=sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1 \ - --hash=sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e - # via - # aiohttp - # aiosignal -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 - # via yarl -multidict==6.0.4 \ - --hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \ - --hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \ - --hash=sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03 \ - --hash=sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710 \ - --hash=sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161 \ - --hash=sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664 \ - --hash=sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569 \ - --hash=sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067 \ - --hash=sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313 \ - --hash=sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706 \ - --hash=sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2 \ - --hash=sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636 \ - --hash=sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49 \ - --hash=sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93 \ - --hash=sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603 \ - --hash=sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0 \ - --hash=sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60 \ - --hash=sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4 \ - --hash=sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e \ - --hash=sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1 \ - --hash=sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60 \ - --hash=sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951 \ - --hash=sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc \ - --hash=sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe \ - --hash=sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95 \ - --hash=sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d \ - --hash=sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8 \ - --hash=sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed \ - --hash=sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2 \ - --hash=sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775 \ - --hash=sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87 \ - --hash=sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c \ - --hash=sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2 \ - --hash=sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98 \ - --hash=sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3 \ - --hash=sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe \ - --hash=sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78 \ - --hash=sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660 \ - --hash=sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176 \ - --hash=sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e \ - --hash=sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988 \ - --hash=sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c \ - --hash=sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c \ - --hash=sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0 \ - --hash=sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449 \ - --hash=sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f \ - --hash=sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde \ - --hash=sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5 \ - --hash=sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d \ - --hash=sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac \ - --hash=sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a \ - --hash=sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9 \ - --hash=sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca \ - --hash=sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11 \ - --hash=sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35 \ - --hash=sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063 \ - --hash=sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b \ - --hash=sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982 \ - --hash=sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258 \ - --hash=sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1 \ - --hash=sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52 \ - --hash=sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480 \ - --hash=sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7 \ - --hash=sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461 \ - --hash=sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d \ - --hash=sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc \ - --hash=sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779 \ - --hash=sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a \ - --hash=sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547 \ - --hash=sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0 \ - --hash=sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171 \ - --hash=sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf \ - --hash=sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d \ - --hash=sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba - # via - # aiohttp - # yarl -pyyaml==6.0.1 \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ - --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ - --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ - --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ - --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ - --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ - --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ - --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ - --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ - --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ - --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ - --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ - --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ - --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ - --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ - --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ - --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ - --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ - --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ - --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ - --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ - --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ - --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ - --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ - --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ - --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ - --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ - --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ - --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ - --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ - --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ - --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ - --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ - --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ - --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ - --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ - --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ - --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ - --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ - --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f - # via -r requirements.in -yarl==1.9.2 \ - --hash=sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571 \ - --hash=sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3 \ - --hash=sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3 \ - --hash=sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c \ - --hash=sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7 \ - --hash=sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04 \ - --hash=sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191 \ - --hash=sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea \ - --hash=sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4 \ - --hash=sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4 \ - --hash=sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095 \ - --hash=sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e \ - --hash=sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74 \ - --hash=sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef \ - --hash=sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33 \ - --hash=sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde \ - --hash=sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45 \ - --hash=sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf \ - --hash=sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b \ - --hash=sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac \ - --hash=sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0 \ - --hash=sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528 \ - --hash=sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716 \ - --hash=sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb \ - --hash=sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18 \ - --hash=sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72 \ - --hash=sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6 \ - --hash=sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582 \ - --hash=sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5 \ - --hash=sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368 \ - --hash=sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc \ - --hash=sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9 \ - --hash=sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be \ - --hash=sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a \ - --hash=sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80 \ - --hash=sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8 \ - --hash=sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6 \ - --hash=sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417 \ - --hash=sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574 \ - --hash=sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59 \ - --hash=sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608 \ - --hash=sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82 \ - --hash=sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1 \ - --hash=sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3 \ - --hash=sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d \ - --hash=sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8 \ - --hash=sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc \ - --hash=sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac \ - --hash=sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8 \ - --hash=sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955 \ - --hash=sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0 \ - --hash=sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367 \ - --hash=sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb \ - --hash=sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a \ - --hash=sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623 \ - --hash=sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2 \ - --hash=sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6 \ - --hash=sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7 \ - --hash=sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4 \ - --hash=sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051 \ - --hash=sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938 \ - --hash=sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8 \ - --hash=sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9 \ - --hash=sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3 \ - --hash=sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5 \ - --hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \ - --hash=sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333 \ - --hash=sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185 \ - --hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \ - --hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560 \ - --hash=sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b \ - --hash=sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7 \ - --hash=sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78 \ - --hash=sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7 - # via aiohttp diff --git a/examples/shared/python/data-service.py b/examples/shared/python/data-service.py deleted file mode 100644 index 944c3b7f5a6c..000000000000 --- a/examples/shared/python/data-service.py +++ /dev/null @@ -1,30 +0,0 @@ -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get('/file.{suffix}') -async def get(request): - suffix = request.match_info["suffix"] - - with open(f"/code/data/file.{suffix}") as f: - if suffix == "txt": - return web.Response(text=f.read()) - return web.json_response(body=f.read()) - - -@routes.post("/upload") -async def post(request): - data = await request.post() - datalen = 0 - for k in data: - datalen += len(k) - resp = web.Response(text="OK") - resp.headers["decompressed-size"] = str(datalen) - return resp - - -if __name__ == "__main__": - app = web.Application(client_max_size=1024**4) - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/shared/python/postgres/requirements.in b/examples/shared/python/postgres/requirements.in deleted file mode 100644 index 37ec460f84e8..000000000000 --- a/examples/shared/python/postgres/requirements.in +++ /dev/null @@ -1 +0,0 @@ -psycopg2-binary diff --git a/examples/shared/python/postgres/requirements.txt b/examples/shared/python/postgres/requirements.txt deleted file mode 100644 index 272d6720b807..000000000000 --- a/examples/shared/python/postgres/requirements.txt +++ /dev/null @@ -1,77 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --generate-hashes requirements.in -# -psycopg2-binary==2.9.9 \ - --hash=sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9 \ - --hash=sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77 \ - --hash=sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e \ - --hash=sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84 \ - --hash=sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3 \ - --hash=sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2 \ - --hash=sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67 \ - --hash=sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876 \ - --hash=sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152 \ - --hash=sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f \ - --hash=sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a \ - --hash=sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6 \ - --hash=sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503 \ - --hash=sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f \ - --hash=sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493 \ - --hash=sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996 \ - --hash=sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f \ - --hash=sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e \ - --hash=sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59 \ - --hash=sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94 \ - --hash=sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7 \ - --hash=sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682 \ - --hash=sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420 \ - --hash=sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae \ - --hash=sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291 \ - --hash=sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe \ - --hash=sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980 \ - --hash=sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692 \ - --hash=sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119 \ - --hash=sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716 \ - --hash=sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472 \ - --hash=sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b \ - --hash=sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2 \ - --hash=sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc \ - --hash=sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c \ - --hash=sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5 \ - --hash=sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984 \ - --hash=sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9 \ - --hash=sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf \ - --hash=sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0 \ - --hash=sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f \ - --hash=sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212 \ - --hash=sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb \ - --hash=sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be \ - --hash=sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90 \ - --hash=sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041 \ - --hash=sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7 \ - --hash=sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860 \ - --hash=sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245 \ - --hash=sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27 \ - --hash=sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417 \ - --hash=sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359 \ - --hash=sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202 \ - --hash=sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0 \ - --hash=sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7 \ - --hash=sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba \ - --hash=sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1 \ - --hash=sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd \ - --hash=sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07 \ - --hash=sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98 \ - --hash=sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55 \ - --hash=sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d \ - --hash=sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972 \ - --hash=sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f \ - --hash=sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e \ - --hash=sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26 \ - --hash=sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957 \ - --hash=sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53 \ - --hash=sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52 - # via -r requirements.in diff --git a/examples/shared/python/service.py b/examples/shared/python/service.py deleted file mode 100644 index 9d79a76d205b..000000000000 --- a/examples/shared/python/service.py +++ /dev/null @@ -1,14 +0,0 @@ -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/") -async def get(request): - return web.Response(text="Hello, World") - - -if __name__ == "__main__": - app = web.Application() - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/shared/python/tracing/service.py b/examples/shared/python/tracing/service.py deleted file mode 100644 index 3a5c786f7eef..000000000000 --- a/examples/shared/python/tracing/service.py +++ /dev/null @@ -1,26 +0,0 @@ -import logging -import os - -from aiohttp import web - -routes = web.RouteTableDef() - - -@routes.get("/{service_type}/{service}") -async def get(request): - service = request.match_info["service"] - print(f"Host: {request.headers.get('Host')}", flush=True) - - service_name = os.environ.get("SERVICE_NAME") - - if service_name and service != service_name: - raise web.HTTPNotFound() - - return web.Response(text=f"Hello from behind Envoy (service {service})!\n") - - -if __name__ == "__main__": - app = web.Application() - logging.basicConfig(level=logging.DEBUG) - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/shared/python/tracing/service2.py b/examples/shared/python/tracing/service2.py deleted file mode 100644 index 6e19ab0a229e..000000000000 --- a/examples/shared/python/tracing/service2.py +++ /dev/null @@ -1,60 +0,0 @@ -import logging -import os -import socket -import sys - -import aiohttp -from aiohttp import web - -routes = web.RouteTableDef() - -TRACE_HEADERS_TO_PROPAGATE = [ - 'X-Ot-Span-Context', - 'X-Request-Id', - - # Zipkin headers - 'X-B3-TraceId', - 'X-B3-SpanId', - 'X-B3-ParentSpanId', - 'X-B3-Sampled', - 'X-B3-Flags', - - # Jaeger header (for native client) - "uber-trace-id", - - # SkyWalking headers. - "sw8" -] - - -@routes.get("/{service_type}/{service}") -async def get(request): - service_type = request.match_info["service_type"] - service = request.match_info["service"] - service_name = os.environ.get("SERVICE_NAME") - - if service_name and service != service_name: - raise web.HTTPNotFound() - - if service_type == "trace" and int(service_name) == 1: - # call service 2 from service 1 - headers = {} - for header in TRACE_HEADERS_TO_PROPAGATE: - if header in request.headers: - headers[header] = request.headers[header] - async with aiohttp.ClientSession() as session: - async with session.get("http://localhost:9000/trace/2", headers=headers) as resp: - pass - - return web.Response( - text=( - f"Hello from behind Envoy (service {service})! " - f"hostname {socket.gethostname()} " - f"resolved {socket.gethostbyname(socket.gethostname())}\n")) - - -if __name__ == "__main__": - app = web.Application() - logging.basicConfig(level=logging.DEBUG) - app.add_routes(routes) - web.run_app(app, host='0.0.0.0', port=8080) diff --git a/examples/shared/python/tracing/start_service.sh b/examples/shared/python/tracing/start_service.sh deleted file mode 100644 index 43a8c112e636..000000000000 --- a/examples/shared/python/tracing/start_service.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -python3 /code/service.py & -envoy -c /etc/service-envoy.yaml --service-cluster "service${SERVICE_NAME}" diff --git a/examples/shared/websocket/Dockerfile b/examples/shared/websocket/Dockerfile deleted file mode 100644 index 4f714ce9fcb7..000000000000 --- a/examples/shared/websocket/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM debian:bookworm-slim@sha256:5f7d5664eae4a192c2d2d6cb67fc3f3c7891a8722cd2903cc35aa649a12b0c8d AS websocket-base -ENV DEBIAN_FRONTEND=noninteractive -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update \ - && apt-get -qq install --no-install-recommends -y ca-certificates musl wget -RUN wget -qO /usr/local/bin/websocat https://github.com/vi/websocat/releases/download/v1.11.0/websocat.x86_64-unknown-linux-musl \ - && echo 'dc5524b9f03a344b88a12c859fb02f8bb56b3373dbc43a6e0c45a2ab52b853d7 /usr/local/bin/websocat' | sha256sum -c - \ - && chmod +x /usr/local/bin/websocat -ENTRYPOINT ["websocat"] - - -FROM websocket-base AS websocket-client -ENV DEBIAN_FRONTEND=noninteractive -ADD interact.sh /interact.sh -RUN chmod +x /interact.sh -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ - apt-get -qq update \ - && apt-get -qq install --no-install-recommends -y expect -ENTRYPOINT ["/interact.sh"] - - -FROM websocket-base diff --git a/examples/single-page-app/_github-clusters.yml b/examples/single-page-app/_github-clusters.yml deleted file mode 100644 index 9d5645ac06a0..000000000000 --- a/examples/single-page-app/_github-clusters.yml +++ /dev/null @@ -1,34 +0,0 @@ - - name: github - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: hub - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: github.com - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: github.com - - name: github-api - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: hub-api - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: api.github.com - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: api.github.com diff --git a/examples/single-page-app/_static/spa-cookies.png b/examples/single-page-app/_static/spa-cookies.png deleted file mode 100644 index ce099ab99fce..000000000000 Binary files a/examples/single-page-app/_static/spa-cookies.png and /dev/null differ diff --git a/examples/single-page-app/_static/spa-github-oauth.png b/examples/single-page-app/_static/spa-github-oauth.png deleted file mode 100644 index 90788486c3eb..000000000000 Binary files a/examples/single-page-app/_static/spa-github-oauth.png and /dev/null differ diff --git a/examples/single-page-app/_static/spa-login-github.png b/examples/single-page-app/_static/spa-login-github.png deleted file mode 100644 index f83c5357910b..000000000000 Binary files a/examples/single-page-app/_static/spa-login-github.png and /dev/null differ diff --git a/examples/single-page-app/_static/spa-login.png b/examples/single-page-app/_static/spa-login.png deleted file mode 100644 index 75471c809428..000000000000 Binary files a/examples/single-page-app/_static/spa-login.png and /dev/null differ diff --git a/examples/single-page-app/_static/spa-resources.png b/examples/single-page-app/_static/spa-resources.png deleted file mode 100644 index 766ad0085258..000000000000 Binary files a/examples/single-page-app/_static/spa-resources.png and /dev/null differ diff --git a/examples/single-page-app/docker-compose.yml b/examples/single-page-app/docker-compose.yml deleted file mode 100644 index 2524dd6d11c9..000000000000 --- a/examples/single-page-app/docker-compose.yml +++ /dev/null @@ -1,82 +0,0 @@ -services: - ui: - build: - context: ../shared/node - target: yarn-routed - volumes: - - ${UI_PATH:-./ui}:/workspace - - ${XDS_PATH:-./xds}:/var/lib/envoy - working_dir: /workspace - - envoy: - depends_on: - ui: - condition: service_healthy - myhub: - condition: service_started - myhub-api: - condition: service_started - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ${ENVOY_CONFIG:-envoy.yml} - ports: - - ${PORT_DEV_PROXY:-10001}:10001 - - ${PORT_PROXY:-10000}:10000 - command: - - envoy - - "-c" - - /etc/envoy.yaml - - "--component-log-level" - - oauth2:trace,http:debug - entrypoint: - - /bin/bash - - -c - - | - set -eo pipefail - touch /var/lib/envoy/lds.yml - chmod +w /var/lib/envoy/lds.yml - exec envoy "$${@}" - volumes: - - ${SECRETS_PATH:-./secrets}:/etc/envoy/secrets - - ${XDS_PATH:-./xds}:/var/lib/envoy - - ${UI_PATH:-./ui}/dist:/var/www/html - - myhub: - build: - context: ../shared/python - target: aiohttp-service - args: - SERVICE_PORT: 7000 - ports: - - ${PORT_MYHUB:-7000}:7000 - volumes: - - myhub:/var/lib/myhub - - ./myhub/myhub.py:/code/service.py - - ./myhub/data.yml:/etc/myhub/data.yml - - ./myhub/images:/var/lib/myhub/images - - ./myhub/shared.py:/code/shared.py - environment: - DATA_PATH: /etc/myhub/data.yml - TOKEN_STORAGE_PATH: /var/lib/myhub/auth.json - - myhub-api: - build: - context: ../shared/python - target: aiohttp-service - args: - SERVICE_PORT: 7000 - volumes: - - myhub:/var/lib/myhub - - ./myhub/api.py:/code/service.py - - ./myhub/data.yml:/etc/myhub/data.yml - - ./myhub/images:/var/lib/myhub/images - - ./myhub/shared.py:/code/shared.py - environment: - DATA_PATH: /etc/myhub/data.yml - MYHUB_URL: "http://localhost:${PORT_MYHUB:-7000}" - TOKEN_STORAGE_PATH: /var/lib/myhub/auth.json - -volumes: - myhub: diff --git a/examples/single-page-app/envoy.yml b/examples/single-page-app/envoy.yml deleted file mode 100644 index a3e497f4bc15..000000000000 --- a/examples/single-page-app/envoy.yml +++ /dev/null @@ -1,325 +0,0 @@ -node: - id: FOO - cluster: BAR - -dynamic_resources: - lds_config: - path_config_source: - path: /var/lib/envoy/lds.yml - -static_resources: - listeners: - - name: dev - address: - socket_address: - protocol: TCP - address: 0.0.0.0 - port_value: 10001 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - upgrade_configs: - - upgrade_type: websocket - http_filters: - - name: envoy.filters.http.oauth2 - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2 - config: - token_endpoint: - cluster: hub - uri: http://myhub:7000/authenticate - timeout: 3s - default_expires_in: 600s - authorization_endpoint: http://localhost:7000/authorize - redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/authorize" - forward_bearer_token: true - pass_through_matcher: - name: ":path" - string_match: - safe_regex: - regex: >- - ^\/(authorize.*|login|logout)$ - invert_match: true - redirect_path_matcher: - path: - prefix: /authorize - signout_path: - path: - exact: /logout - credentials: - client_id: "0123456789" - token_secret: - name: token - sds_config: - path_config_source: - path: /etc/envoy/secrets/myhub-token-secret.yml - hmac_secret: - name: hmac - sds_config: - path_config_source: - path: /etc/envoy/secrets/hmac-secret.yml - auth_scopes: - - user:email - - name: envoy.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - codec_type: "AUTO" - stat_prefix: ingress_http - route_config: - virtual_hosts: - - name: web - domains: ["*"] - routes: - - match: - prefix: "/hub/" - route: - host_rewrite_literal: api.myhub - regex_rewrite: - pattern: - regex: '^/hub/(.*)' - substitution: '/\1' - cluster: hub-api - - match: - prefix: "/" - route: - cluster: ui - - - name: production - address: - socket_address: - protocol: TCP - address: 0.0.0.0 - port_value: 10000 - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StderrAccessLog - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - http_filters: - - name: envoy.filters.http.oauth2 - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2 - config: - token_endpoint: - cluster: hub - uri: http://myhub:7000/authenticate - timeout: 3s - default_expires_in: 600s - authorization_endpoint: http://localhost:7000/authorize - redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/authorize" - forward_bearer_token: true - pass_through_matcher: - name: ":path" - string_match: - safe_regex: - regex: >- - ^\/(authorize.*|login|logout)$ - invert_match: true - redirect_path_matcher: - path: - prefix: /authorize - signout_path: - path: - exact: /logout - credentials: - client_id: "0123456789" - token_secret: - name: token - sds_config: - path_config_source: - path: /etc/envoy/secrets/myhub-token-secret.yml - hmac_secret: - name: hmac - sds_config: - path_config_source: - path: /etc/envoy/secrets/hmac-secret.yml - auth_scopes: - - user:email - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip - memory_level: 3 - window_bits: 10 - - name: envoy.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - codec_type: "AUTO" - stat_prefix: ingress_http - route_config: - virtual_hosts: - - name: web - domains: ["*"] - routes: - - match: - prefix: "/other/" - route: - regex_rewrite: - pattern: - regex: '^/other/(.*)' - substitution: '/\1' - cluster: other - - - match: - prefix: "/hub/" - route: - host_rewrite_literal: api.myhub - regex_rewrite: - pattern: - regex: '^/hub/(.*)' - substitution: '/\1' - cluster: hub-api - - match: - prefix: "/" - route: - cluster: loopback - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - # UI development server - # tail the logs by running: - # `docker compose logs ui -f` - - name: ui - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: ui - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: ui - port_value: 3000 - - # UI static routes (production) - # build app and create listener/routes by running: - # `docker compose run ui build.sh` - - name: loopback - type: STATIC - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: loopback - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 10002 - - - name: hub - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: hub - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: myhub - port_value: 7000 - - - name: hub-api - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: hub-api - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: myhub-api - port_value: 7000 - - - name: other - type: LOGICAL_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: other - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: other - port_value: 7000 diff --git a/examples/single-page-app/example.rst b/examples/single-page-app/example.rst deleted file mode 100644 index ea702bda6f5f..000000000000 --- a/examples/single-page-app/example.rst +++ /dev/null @@ -1,650 +0,0 @@ -.. _install_sandboxes_single_page_app: - -Single page React app (with OAuth) -================================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make HTTP requests. - - :ref:`envsubst ` - Used to interpolate environment vars in templates. - - :ref:`jq ` - Used to parse JSON. - - :ref:`mkpasswd ` - Used to generate a ~random HMAC token. - -This sandbox provides an example of building and developing a single page app with Envoy. - -The sandbox covers a number of Envoy's features, including: - -- :ref:`direct_response ` -- :ref:`OAuth ` -- Dynamic xDS filesystem updates -- Websocket proxy -- Gzip :ref:`compression ` -- TLS/SNI up/downstream connection/termination -- Path/host rewrites - -The app is built with `React `__ using `Vite `__ and demonstrates OAuth authentication using -Envoy's :ref:`OAuth filter `. - -This covers a scenario where we want OAuth to both authenticate the user and provide credentials -for further API interactions. - -This is enabled by setting the OAuth configuration -:ref:`forward_bearer_token ` -to ``true`` - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 36-40 - :linenos: - :lineno-start: 36 - :emphasize-lines: 3 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -.. warning:: - Setting - :ref:`forward_bearer_token ` - means the provided access token will be forwarded to any cluster/upstreams proxied by Envoy for this HTTP filter chain.. - - If untrusted upstreams are present, care will need to be taken to remove any sensitive cookies, such as ``BearerToken``. - - This can be achieved by setting :ref:`request_headers_to_remove ` - for the affected route. - -A dummy "Myhub" backend is provided with a minimal OAuth provider and API for use in the example. - -Setup is provided to :ref:`build and update the app for production use `, -as well as a :ref:`development environment ` with -:ref:`automatic code reloading `. - -The production and development environments are exposed on ports ``10000`` and ``10001`` respectively. - -The Myhub backend can easily be replaced with `Github `__ or some other OAuth-based upstream service, -and some :ref:`guidance is provided on how to do this `. - -.. _install_sandboxes_single_page_app_step_local: - -Step 1: Create a ``.local`` directory for sandbox customizations -**************************************************************** - -Change to the ``examples/single-page-app`` directory, and create a directory to store sandbox customizations. - -You can use ``.local`` which will be ignored by Git: - -.. code-block:: console - - $ mkdir .local - -Copy the ``ui/`` directory to ``.local`` and set the ``UI_PATH``. This will allow customizations without changing committed files. - -.. code-block:: console - - $ cp -a ui .local - $ export UI_PATH=./.local/ui - -.. _install_sandboxes_single_page_app_step_hmac: - -Step 2: Generate an HMAC secret -******************************* - -Envoy's :ref:`OAuth filter ` requires an HMAC secret for encoding credentials. - -Copy the default sandbox secrets to the customization directory, and create the required HMAC secret. - -Replace ``MY_HMAC_SECRET_SEED`` with a phrase of your choosing: - -.. code-block:: console - - $ cp -a secrets .local - $ HMAC_SECRET=$(echo "MY_HMAC_SECRET_SEED" | mkpasswd -s) - $ export HMAC_SECRET - $ envsubst < hmac-secret.tmpl.yml > .local/secrets/hmac-secret.yml - -Export the path to the secrets folder for Docker: - -.. code-block:: console - - $ export SECRETS_PATH=./.local/secrets - -.. _install_sandboxes_single_page_app_step_start: - -Step 3: Start the containers -**************************** - -First export ``UID`` to ensure files created by the containers are created with your user id. - -Then bring up the Docker composition: - -.. code-block:: console - - $ pwd - envoy/examples/single-page-app - $ export UID - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS - --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - single-page-app-envoy-1 single-page-app-envoy "/docker-entrypoint.sh envoy -c /etc/envoy/envoy.yaml ..." envoy 2 minutes ago Up 2 minutes 0.0.0.0:10000-10001->10000-10001/tcp, :::10000-10001->10000-10001/tcp - single-page-app-myhub-1 single-page-app-myhub "/opt/myhub/app.py" myhub 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:7000->7000/tcp, :::7000->7000/tcp - single-page-app-myhub-api-1 single-page-app-myhub-api "/opt/myhub/app.py" myhub-api 2 minutes ago Up 2 minutes (healthy) - single-page-app-ui-1 single-page-app-ui "/entrypoint.sh dev.sh" ui 2 minutes ago Up 2 minutes (healthy) - -.. _install_sandboxes_single_page_app_step_login: - -Step 4: Browse to the dev app and login -*************************************** - -The development app should now be available at http://localhost:10001 and provide a login button: - -.. image:: /start/sandboxes/_include/single-page-app/_static/spa-login.png - :align: center - -.. note:: - The dummy OAuth provider automatically trusts everyone as a hard-coded ``envoydemo`` user and redirects back to the app. - - In a real world scenario the provider would authenticate and authorize the user before proceeding. - -The sandbox is configured with an inverted match on -:ref:`pass_through_matcher `. - -This ignores all paths for OAuth other than: - -- ``/authorize.*`` -- ``/hub.*`` -- ``/login`` -- ``/logout``. - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 37-46 - :linenos: - :lineno-start: 37 - :emphasize-lines: 3-8 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -When a user clicks ``login`` the app initiates the OAuth flow by calling the ``/login`` path in Envoy. - -This redirects the user to the OAuth provider for authorization/authentication with a further redirect link: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 34-39 - :linenos: - :lineno-start: 34 - :emphasize-lines: 3-4 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -On successful authorization/authentication the user is redirected back via this link to the app with the necessary OAuth -`authorization code `__ to proceed: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 44-50 - :linenos: - :lineno-start: 44 - :emphasize-lines: 3-5 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -Envoy then uses this authorization code with its client secret to confirm authorization and obtain an access token for the user: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 50-61 - :linenos: - :lineno-start: 50 - :emphasize-lines: 3-10 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -.. literalinclude:: _include/single-page-app/secrets/myhub-token-secret.yml - :language: yaml - :linenos: - :emphasize-lines: 6 - :caption: :download:`myhub-token-secret.yml <_include/single-page-app/secrets/myhub-token-secret.yml>` - -Once logged in, you should be able to make queries to the API using the OAuth credentials: - -.. image:: /start/sandboxes/_include/single-page-app/_static/spa-resources.png - :align: center - -.. warning:: - Envoy's OAuth implementation defaults to triggering the OAuth flow for all paths on the endpoint. - - This can readily trigger an OAuth flood as assets are requested, and doom loops when the OAuth flows fail. - - This can be avoided by restricting the paths that are used by the OAuth flow. - - The sandbox example does this by inverting the - :ref:`pass_through_matcher ` - to only match on the required OAuth paths. - -.. tip:: - The Myhub OAuth provider does not provide an expiry for issued credentials. Likewise Github may or may - not depending on configuration. This is valid in terms of the OAuth2 specification. - - If the authorization provider does not include an expiry, Envoy will, by default, fail the authentication. - - This can be resolved by setting - :ref:`default_expires_in `: - - .. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 33-37 - :linenos: - :lineno-start: 33 - :emphasize-lines: 3 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -.. _install_sandboxes_single_page_app_step_api: - -Step 5: Make API queries -************************ - -For the sandbox app, -:ref:`forward_bearer_token ` -is set, and so Envoy also passes the acquired access token back to the user as a cookie: - -.. image:: /start/sandboxes/_include/single-page-app/_static/spa-cookies.png - :align: center - -This cookie is then passed through Envoy in any subsequent requests to the proxied Myhub API: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 76-88 - :linenos: - :lineno-start: 76 - :emphasize-lines: 3-11 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -.. _install_sandboxes_single_page_app_step_reload: - -Step 6: Live reload code changes -******************************** - -With your browser open on http://localhost:10001 make some change to the UI. - -For example, you might change the page title: - -.. code-block:: console - - $ sed -i s/Envoy\ single\ page\ app\ example/DEV\ APP/g .local/ui/index.html - -The page should automatically refresh. - -Likewise any changes to the Typescript app components in ``.local/ui/src/...`` should automatically reload in -the browser. - -This is enabled in Envoy by allowing the proxied connection to the `Vite `__ -development backend to be "upgraded" to use Websockets: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 22-27 - :linenos: - :lineno-start: 22 - :emphasize-lines: 3-4 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -You can view the logs for the development server with: - -.. code-block:: console - - $ docker compose logs ui - single-page-app-ui-1 | Starting (dev.sh) with user: 1000 worker /home/worker - single-page-app-ui-1 | yarn run v1.22.19 - single-page-app-ui-1 | $ vite --host 0.0.0.0 --port 3000 - single-page-app-ui-1 | - single-page-app-ui-1 | VITE v5.0.10 ready in 119 ms - single-page-app-ui-1 | - single-page-app-ui-1 | ➜ Local: http://localhost:3000/ - single-page-app-ui-1 | ➜ Network: http://172.30.0.5:3000/ - -You can also use ``docker attach`` should you want to interact with the process. - -.. tip:: - You can manage the Typescript package using `Yarn `__: - - .. code-block:: console - - $ docker compose run --rm ui yarn - -.. _install_sandboxes_single_page_app_step_logout: - -Step 7: Log out of the app -************************** - -On signing out, the app makes a request to Envoy's configured -:ref:`signout_path `: - -.. literalinclude:: _include/single-page-app/envoy.yml - :language: yaml - :lines: 47-53 - :linenos: - :lineno-start: 47 - :emphasize-lines: 3-5 - :caption: :download:`envoy.yml <_include/single-page-app/envoy.yml>` - -This clears the cookies and the credentials stored by Envoy before returning the user to the app home page. - -The app also clears any stored data associated with the user session: - -.. _install_sandboxes_single_page_app_step_production_build: - -Step 8: Build production assets -******************************* - -First, create and set a custom ``xds/`` directory. - -You will need to rebuild Envoy to ensure it sees the correct directory: - -.. code-block:: console - - $ mkdir .local/production - $ cp -a xds .local/production/ - $ export XDS_PATH=./.local/production/xds - $ docker compose up --build -d envoy - -You can build the production assets for the app with the following: - -.. code-block:: console - - $ docker compose run --rm ui build.sh - -After building the `React `__ app, the sandbox script automatically updates Envoy's configuration with the -static routes required to serve the app. - -You can view the generated routes: - -.. code-block:: console - - $ jq '.resources[0].filter_chains[0].filters[0].typed_config.route_config.virtual_hosts[0].routes' < .local/production/xds/lds.yml - -.. code-block:: json - - [ - { - "match": { - "path": "/assets/index-dKz4clFg.js" - }, - "direct_response": { - "status": 200, - "body": { - "filename": "/var/www/html/assets/index-dKz4clFg.js" - } - }, - "response_headers_to_add": [ - { - "header": { - "key": "Content-Type", - "value": "text/javascript" - } - } - ] - }, - { - "match": { - "path": "/myhub.svg" - }, - "direct_response": { - "status": 200, - "body": { - "filename": "/var/www/html/myhub.svg" - } - }, - "response_headers_to_add": [ - { - "header": { - "key": "Content-Type", - "value": "image/svg+xml" - } - } - ] - }, - { - "match": { - "prefix": "/" - }, - "direct_response": { - "status": 200, - "body": { - "filename": "/var/www/html/index.html" - } - }, - "response_headers_to_add": [ - { - "header": { - "key": "Content-Type", - "value": "text/html" - } - } - ] - } - ] - -.. note:: - This setup configures Envoy to store the necessary files in memory. - - This may be a good fit for the single page app use case, but would not scale well - for many or large files. - -.. tip:: - When you make changes to the javascript/typescript files rebuilding the app creates new routes to the - compiled assets. - - In this case Envoy will update via xDS and use the newly routed assets. - - If you make changes only to assets that do not get a new route - e.g. ``index.html`` - you - should both rebuild the app and restart Envoy after: - - .. code-block:: console - - $ docker compose run --rm ui build.sh - $ docker compose restart envoy - -.. _install_sandboxes_single_page_app_step_production_browse: - -Step 9: Browse to the production server -*************************************** - -You can browse to this server on https://localhost:10000 - -Unlike the development endpoint the production endpoint is configured with: - -- TLS (self-signed) -- Gzip compression -- Statically served assets - -.. _install_sandboxes_single_page_app_step_github_oauth: - -Step 10: Setup Github OAuth/API access -************************************** - -.. tip:: - Setup for `Github `__ is explained in this sandbox, but it should be easy to adapt these instructions for other providers. - -You will need to set up either a `Github OAuth or full app `__. The latter provides -more control and is generally preferable. - -This can be done either at the `user `_ or organization levels: - -.. image:: /start/sandboxes/_include/single-page-app/_static/spa-github-oauth.png - :align: center - -.. note:: - - When setting up `Github OAuth `__ you will need to provide the redirect URI - - This must match the configured URI in Envoy - - For the purposes of this example set it to https://localhost:10000. - - You will need a separate OAuth app for development. - -Depending on your use case, you may also want to set up any permissions required for your app. - -Once you have this set up, you will need the `provided client id and secret `__. - -.. _install_sandboxes_single_page_app_step_github_config: - -Step 11: Update Envoy's configuration to use Github -*************************************************** - -Add the `Github provided client secret `__: - -.. code-block:: console - - $ TOKEN_SECRET="GITHUB PROVIDED CLIENT SECRET" - $ export TOKEN_SECRET - $ envsubst < secrets/token-secret.tmpl.yml > .local/secrets/github-token-secret.yml - -The file created will be available in the container under ``/etc/envoy/secrets`` - -.. tip:: - The following instructions use ``sed``, but you may wish to make the necessary replacements - using your editor. - - For each configuration there are 2 places to update, one for the development listener and the other for production. - -Create a copy of the Envoy config and tell Docker to use it: - -.. code-block:: console - - $ cp -a envoy.yml .local/envoy.yml - $ export ENVOY_CONFIG=.local/envoy.yml - -For the OAuth configuration in ``.local/envoy.yml`` set the `Github provided client secret `__: - -.. code-block:: console - - $ sed -i s@client_id:\ \"0123456789\"@client_id:\ \"$GITHUB_PROVIDED_CLIENT_ID\"@g .local/envoy.yml - -Replace the -:ref:`authorization_endpoint ` -with ``https://github.com/login/oauth/authorize``: - -.. code-block:: console - - $ sed -i s@authorization_endpoint:\ http://localhost:7000/authorize@authorization_endpoint:\ https://github.com/login/oauth/authorize@g .local/envoy.yml - -Replace the -:ref:`token_endpoint ` > -:ref:`uri ` -with ``https://github.com/login/oauth/access_token``: - -.. code-block:: console - - $ sed -i s@uri:\ http://myhub:7000/authenticate@uri:\ https://github.com/login/oauth/access_token@g .local/envoy.yml - -Point the -:ref:`token_secret ` > -:ref:`path ` -to the ``github-token-secret.yml`` created above: - -.. code-block:: console - - $ sed -i s@path:\ /etc/envoy/secrets/myhub-token-secret.yml@path:\ /etc/envoy/secrets/github-token-secret.yml@g .local/envoy.yml - -Replace the :ref:`host rewrites `: - -.. code-block:: console - - $ sed -i s@host_rewrite_literal:\ api.myhub@host_rewrite_literal:\ api.github.com@g .local/envoy.yml - -Finally add (or replace the ``myhub*`` clusters with) the ``github`` and ``github-api`` clusters -:download:`Github configured clusters <_include/single-page-app/_github-clusters.yml>`: - -.. code-block:: console - - $ cat _github-clusters.yml >> .local/envoy.yml - -Step 12: Update the app configuration to use Github -*************************************************** - -We need to tell the app the name of the provider. - -Currently providers for Myhub and `Github `__ are implemented: - -.. literalinclude:: _include/single-page-app/ui/src/providers.tsx - :language: typescript - :lines: 7-13 - :linenos: - :lineno-start: 7 - :caption: :download:`providers.tsx <_include/single-page-app/ui/src/providers.tsx>` - -If you followed the above steps, the `Vite `__ app environment settings are read from ``.local/ui/.env*``: - -.. code-block:: console - - $ echo "VITE_APP_AUTH_PROVIDER=github" > .local/ui/.env.local - -.. _install_sandboxes_single_page_app_step_github_restart: - -Step 13: Rebuild the app and restart Envoy -****************************************** - -.. code-block:: console - - $ docker compose run --rm ui build.sh - $ docker compose up --build -d envoy - -.. tip:: - Note the use of ``up --build -d`` rather than ``restart``. - - This is necessary as we have changed ``envoy.yml`` which is loaded into the container at build time. - -Browse to the production server https://localhost:10000 - -You can now log in and use the `Github APIs `__.: - -.. image:: /start/sandboxes/_include/single-page-app/_static/spa-login-github.png - :align: center - -.. seealso:: - - :ref:`Envoy OAuth filter ` - Configuration reference for Envoy's OAuth filter. - - :ref:`Envoy OAuth filter API ` - API reference for Envoy's OAuth filter. - - `OAuth2 specification `__ - OAuth 2.0 is the industry-standard protocol for authorization. - - `React `__ - The library for web and native user interfaces. - - `Vite `__ - Next Generation Frontend Tooling. - - :ref:`Envoy Gzip Compression API ` - API and configuration reference for Envoy's gzip compression. - - :ref:`Securing Envoy quick start guide ` - Outline of key concepts for securing Envoy. - - `Github OAuth apps `__ - Information about setting up `Github `__ OAuth apps. - - `Github API `__ - References for `Github `__'s APIs. - - -.. _github: https://github.com/ -.. _github-api: https://api.github.com/ -.. _github-oauth: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps -.. _github-oauth-credentials: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#2-users-are-redirected-back-to-your-site-by-github -.. _github-user-settings: https://github.com/settings/developers -.. _oauth-auth-code: https://oauth.net/2/grant-types/authorization-code/ -.. _oauth-spec: https://oauth.net/2/ -.. _react: https://react.dev/ -.. _vite: https://vitejs.dev/ -.. _yarn: https://yarnpkg.com/ diff --git a/examples/single-page-app/hmac-secret.tmpl.yml b/examples/single-page-app/hmac-secret.tmpl.yml deleted file mode 100644 index 972ae5c507ba..000000000000 --- a/examples/single-page-app/hmac-secret.tmpl.yml +++ /dev/null @@ -1,6 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret - name: hmac - generic_secret: - secret: - inline_string: $HMAC_SECRET diff --git a/examples/single-page-app/myhub/api.py b/examples/single-page-app/myhub/api.py deleted file mode 100755 index 2204dc08e40b..000000000000 --- a/examples/single-page-app/myhub/api.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 - -# Dummy Github-like API with OAuth - -# NOTE: This is a partial and insecure implementation for testing only - -import json -import logging -import os -import pathlib -import secrets -import urllib.parse - -import yaml - -from aiohttp import web - -from shared import Data, debug_request, TokenStorage - -logger = logging.getLogger(__name__) -MYHUB_URL = os.environ.get("MYHUB_URL") or "http://localhost:7000" - -# TODO: add to app -# Note: You should not persist data in this way for any production system! -token_storage = TokenStorage(pathlib.Path(os.environ["TOKEN_STORAGE_PATH"])) - - -async def user(request): - debug_request(request, "user") - _data = Data(pathlib.Path(os.environ["DATA_PATH"])) - access_token = request.cookies["BearerToken"] - if access_token not in token_storage: - raise web.HTTPForbidden() - user_id = token_storage[access_token]["user_id"] - user = _data["users"][user_id] - user["avatar_url"] = f"{MYHUB_URL}/images{user['avatar_url']}" - for resource in ["public_repos", "followers", "following"]: - user[resource] = len(user[resource]) - return web.json_response(user, dumps=_dumps) - - -async def resources(request): - resource_type = request.match_info["resource"] - debug_request(request, resource_type) - _data = Data(pathlib.Path(os.environ["DATA_PATH"])) - access_token = request.cookies.get("BearerToken") - allowed = ( - access_token - and (token_storage.get(access_token, {}).get("user_id") == request.match_info["user"])) - if not allowed: - raise web.HTTPForbidden() - user = _data["users"].get(request.match_info["user"]) - if not user: - raise web.HttpNotFound() - if resource_type == "repos": - resources = [ - dict( - html_url=f"{MYHUB_URL}/{user['login']}/{resource}", - updated_at=_data["repos"][resource]["updated_at"], - full_name=f"{user['login']}/{resource}") for resource in user["public_repos"] - ] - elif resource_type in ["followers", "following"]: - resources = [ - dict( - avatar_url=f"{MYHUB_URL}/images{_data['users'][related_user]['avatar_url']}", - name=_data['users'][related_user]["name"], - html_url=f"{MYHUB_URL}/users/{related_user}", - login=related_user) for related_user in user[resource_type] - ] - else: - raise web.HTTPNotFound() - return web.json_response(resources, dumps=_dumps) - - -def _dumps(s): - return json.dumps(s, separators=(',', ':')) - - -def main(): - logging.basicConfig(level=logging.DEBUG) - app = web.Application() - app.router.add_route("GET", '/user', user) - app.router.add_route("GET", '/users/{user}/{resource}', resources) - web.run_app(app, port=7000) - - -if __name__ == '__main__': - main() diff --git a/examples/single-page-app/myhub/data.yml b/examples/single-page-app/myhub/data.yml deleted file mode 100644 index b88178e5bec5..000000000000 --- a/examples/single-page-app/myhub/data.yml +++ /dev/null @@ -1,40 +0,0 @@ -users: - envoydemo: - avatar_url: /users/envoy.svg - followers: - - user0 - - user1 - - user3 - following: - - user0 - - user2 - name: Envoy Demo - login: envoydemo - public_repos: - - repo0 - - repo1 - - repo2 - user0: - avatar_url: /users/user0.png - name: User 0 - login: user0 - user1: - avatar_url: /users/user1.png - name: User 1 - login: user1 - user2: - avatar_url: /users/user2.png - name: User 2 - login: user2 - user3: - avatar_url: /users/user3.png - name: User 3 - login: user3 - -repos: - repo0: - updated_at: September 14, 2022 - repo1: - updated_at: February 3, 2023 - repo2: - updated_at: July 28, 2023 diff --git a/examples/single-page-app/myhub/images/users/envoy.svg b/examples/single-page-app/myhub/images/users/envoy.svg deleted file mode 100644 index 124f6dfc1a2a..000000000000 --- a/examples/single-page-app/myhub/images/users/envoy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/single-page-app/myhub/images/users/user0.png b/examples/single-page-app/myhub/images/users/user0.png deleted file mode 100644 index 2df2b4f6ede4..000000000000 Binary files a/examples/single-page-app/myhub/images/users/user0.png and /dev/null differ diff --git a/examples/single-page-app/myhub/images/users/user1.png b/examples/single-page-app/myhub/images/users/user1.png deleted file mode 100644 index 7f9d66598d94..000000000000 Binary files a/examples/single-page-app/myhub/images/users/user1.png and /dev/null differ diff --git a/examples/single-page-app/myhub/images/users/user2.png b/examples/single-page-app/myhub/images/users/user2.png deleted file mode 100644 index b5d5bf37eca8..000000000000 Binary files a/examples/single-page-app/myhub/images/users/user2.png and /dev/null differ diff --git a/examples/single-page-app/myhub/images/users/user3.png b/examples/single-page-app/myhub/images/users/user3.png deleted file mode 100644 index 90491954d85e..000000000000 Binary files a/examples/single-page-app/myhub/images/users/user3.png and /dev/null differ diff --git a/examples/single-page-app/myhub/myhub.py b/examples/single-page-app/myhub/myhub.py deleted file mode 100755 index 0f7d2d203d22..000000000000 --- a/examples/single-page-app/myhub/myhub.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python3 - -# Dummy Github-like repository website with OAuth - -# NOTE: This is a partial and insecure implementation for testing only - -# This is an implementation of a dummy OAuth provider for testing purposes only. -# Authorization is automatic on request - no real authorization or authentication -# is done. - -import logging -import os -import pathlib -import secrets -import urllib.parse - -from aiohttp import web - -from shared import Data, debug_request, TokenStorage - -# Demo envoy user, gets rid of rodents 8/ -DEMOUSER = "envoydemo" - -logger = logging.getLogger(__name__) - -# TODO: add to app -# Note: You should not persist data in this way for any production system! -token_storage = TokenStorage(pathlib.Path(os.environ["TOKEN_STORAGE_PATH"])) - - -async def authorize(request): - debug_request(request, "authorization") - # Generate a random authorization code - authorization_code = secrets.token_hex(16) - logger.debug(f"Generated authorization code: {authorization_code}") - # Store the authorization code - token_storage[authorization_code] = { - "user_id": DEMOUSER, - "client_id": request.query["client_id"] - } - # Redirect the user back to the client with the authorization code - state = urllib.parse.quote(request.query["state"], safe="") - redirect_uri = f"{request.query['redirect_uri']}?code={authorization_code}&state={state}" - logger.debug(f"Redirecting user: {redirect_uri}") - return web.HTTPFound(redirect_uri) - - -async def authenticate(request): - debug_request(request, "authentication") - # Extract the authorization code from the request - content = urllib.parse.parse_qs(await request.text()) - authorization_code = content.get("code")[0] - logger.debug(f"Extracted authorization code: {authorization_code}") - - # Verify the authorization code - if authorization_code not in token_storage: - logger.debug(f"Authentication failed") - return web.HTTPBadRequest(text="Invalid authorization code") - - # Generate an access token - access_token = secrets.token_hex(16) - logger.debug(f"Generated access token: {access_token}") - - # Store the access token and remove authorization code - token_storage[access_token] = token_storage.pop(authorization_code) - - # Return the access token as JSON - return web.json_response({"access_token": access_token, "token_type": "bearer"}) - - -async def repo(request): - debug_request(request, "repo") - _data = Data(pathlib.Path(os.environ["DATA_PATH"])) - user = _data["users"].get(request.match_info["user"]) - if not user: - raise web.HTTPNotFound() - repos = user.get("public_repos", {}) - if request.match_info["repo"] not in repos: - raise web.HTTPNotFound() - return web.Response( - body=f"Myhub repo: {request.match_info['user']}/{request.match_info['repo']}") - - -async def user(request): - debug_request(request, "user") - _data = Data(pathlib.Path(os.environ["DATA_PATH"])) - user = _data["users"].get(request.match_info["user"]) - if not user: - raise web.HTTPNotFound() - return web.Response(body=f"Myhub user: {request.match_info['user']}") - - -def main(): - logging.basicConfig(level=logging.DEBUG) - app = web.Application() - app.router.add_route("GET", '/authorize', authorize) - app.router.add_route("POST", '/authenticate', authenticate) - app.router.add_routes([web.static('/images', "/var/lib/myhub/images")]) - app.router.add_route("GET", '/users/{user}', user) - app.router.add_route("GET", '/{user}/{repo}', repo) - web.run_app(app, port=7000) - - -if __name__ == '__main__': - main() diff --git a/examples/single-page-app/myhub/shared.py b/examples/single-page-app/myhub/shared.py deleted file mode 100644 index 964abd09aa29..000000000000 --- a/examples/single-page-app/myhub/shared.py +++ /dev/null @@ -1,67 +0,0 @@ -import json -import logging -import pathlib -from functools import cached_property -from typing import Optional - -import yaml - -logger = logging.getLogger(__name__) - - -def debug_request(request, resource): - logger.debug( - f"Received {resource} request:\n {request.query}\n {request.cookies}\n {request.match_info}" - ) - - -class Data: - - def __init__(self, path: pathlib.Path) -> None: - self._path = path - - def __contains__(self, k: str) -> bool: - return k in self._data - - def __getitem__(self, k: str) -> str: - return self._data.__getitem__(k) - - def __str__(self) -> str: - return json.dumps(self._data) - - @property - def _data(self) -> dict: - return yaml.safe_load(self._storage.open()) - - @cached_property - def _storage(self) -> pathlib.Path: - return self._path - - def get(self, k: str, default: Optional[str] = None) -> str: - data = self._data - return data.get(k, default) - - -class TokenStorage(Data): - - @property - def _data(self): - return json.load(self._storage.open()) - - @cached_property - def _storage(self): - if not self._path.exists(): - self._path.parent.mkdir(exist_ok=True, parents=True) - self._path.write_text('{}') - return self._path - - def __setitem__(self, k: str, v: str) -> None: - data = self._data - data[k] = v - json.dump(data, self._storage.open("w")) - - def pop(self, k: str) -> str: - data = self._data - result = data.pop(k) - json.dump(data, self._storage.open("w")) - return result diff --git a/examples/single-page-app/secrets/myhub-token-secret.yml b/examples/single-page-app/secrets/myhub-token-secret.yml deleted file mode 100644 index fac6fbd56dcd..000000000000 --- a/examples/single-page-app/secrets/myhub-token-secret.yml +++ /dev/null @@ -1,6 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret - name: token - generic_secret: - secret: - inline_string: VERY_SECRET_KEY diff --git a/examples/single-page-app/token-secret.tmpl.yml b/examples/single-page-app/token-secret.tmpl.yml deleted file mode 100644 index 16ca84f645d2..000000000000 --- a/examples/single-page-app/token-secret.tmpl.yml +++ /dev/null @@ -1,6 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret - name: token - generic_secret: - secret: - inline_string: $TOKEN_SECRET diff --git a/examples/single-page-app/ui/.env b/examples/single-page-app/ui/.env deleted file mode 100644 index a2e84adc9e76..000000000000 --- a/examples/single-page-app/ui/.env +++ /dev/null @@ -1 +0,0 @@ -VITE_APP_AUTH_PROVIDER=myhub diff --git a/examples/single-page-app/ui/.env.development b/examples/single-page-app/ui/.env.development deleted file mode 100644 index 12bd20d336c9..000000000000 --- a/examples/single-page-app/ui/.env.development +++ /dev/null @@ -1 +0,0 @@ -VITE_APP_API_URL=http://localhost:10001 diff --git a/examples/single-page-app/ui/.env.production b/examples/single-page-app/ui/.env.production deleted file mode 100644 index 366c3c4a1ecd..000000000000 --- a/examples/single-page-app/ui/.env.production +++ /dev/null @@ -1 +0,0 @@ -VITE_APP_API_URL=https://localhost:10000 diff --git a/examples/single-page-app/ui/.eslintrc.yml b/examples/single-page-app/ui/.eslintrc.yml deleted file mode 100644 index c812102edd82..000000000000 --- a/examples/single-page-app/ui/.eslintrc.yml +++ /dev/null @@ -1,29 +0,0 @@ -root: true -env: - browser: true - es2021: true -extends: -- eslint:recommended -- plugin:@typescript-eslint/recommended -- plugin:react-hooks/recommended -- plugin:react/recommended -ignorePatterns: -- dist -parser: "@typescript-eslint/parser" -parserOptions: - ecmaFeatures: - jsx: true -plugins: -- react-refresh -- react -rules: - "react-refresh/only-export-components": - - warn - - allowConstantExport: true - object-curly-spacing: - - error - - never - "react/react-in-jsx-scope": off -settings: - react: - version: detect diff --git a/examples/single-page-app/ui/index.html b/examples/single-page-app/ui/index.html deleted file mode 100644 index 8910338f5f10..000000000000 --- a/examples/single-page-app/ui/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Envoy single page app example - - -
- - - diff --git a/examples/single-page-app/ui/package.json b/examples/single-page-app/ui/package.json deleted file mode 100644 index 82f7a868fd44..000000000000 --- a/examples/single-page-app/ui/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "app0", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "preview": "vite preview" - }, - "dependencies": { - "@chakra-ui/icons": "^2.1.1", - "@chakra-ui/react": "^2.8.2", - "@emotion/react": "^11.13.0", - "@emotion/styled": "^11.13.0", - "framer-motion": "^11.3.19", - "mdi-react": "^9.3.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.25.1" - }, - "devDependencies": { - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "@vitejs/plugin-react": "^4.3.1", - "eslint": "^8.57.0", - "eslint-config-standard-with-typescript": "^43.0.0", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.6.0", - "eslint-plugin-react": "^7.35.0", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-react-refresh": "^0.4.9", - "typescript": "*", - "vite": "^5.3.5" - } -} diff --git a/examples/single-page-app/ui/public/envoy.svg b/examples/single-page-app/ui/public/envoy.svg deleted file mode 100644 index d7f5bcc45c11..000000000000 --- a/examples/single-page-app/ui/public/envoy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/single-page-app/ui/public/myhub.svg b/examples/single-page-app/ui/public/myhub.svg deleted file mode 100644 index 7d65673545b4..000000000000 --- a/examples/single-page-app/ui/public/myhub.svg +++ /dev/null @@ -1,496 +0,0 @@ - - - - -Created by potrace 1.16, written by Peter Selinger 2001-2019 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/single-page-app/ui/src/@types/app.d.ts b/examples/single-page-app/ui/src/@types/app.d.ts deleted file mode 100644 index cecd3fb3f8c7..000000000000 --- a/examples/single-page-app/ui/src/@types/app.d.ts +++ /dev/null @@ -1,136 +0,0 @@ - -import {ReactNode} from 'react' - -// user - -export interface IAuthPayload { - isLoggedIn: boolean - user: IUser -} - -export interface IAuthAction { - email?: string - payload?: IAuthPayload - type: string -} - -export interface IUserLogin { - avatar_url: string - html_url: string - login: string - name: string -} - -export interface IUser { - avatar_url: string - email: string - followers: number - following: number - login: string - public_repos: string[] -} - -export interface IAuthProvider { - name: string - icon: T -} - -export interface IAuthProviders { - [key: string]: IAuthProvider -} - -export interface IAuthState { - authenticating: boolean - failed: boolean - isLoggedIn: boolean - user: IUser | null - provider: string - proxy_url: string -} - -export type TAuthContext = { - state: IAuthState - dispatch: React.Dispatch -} - -// data - -export interface IRepo { - html_url: string -} - -export interface IFollower { - avatar_url: string - html_url: string -} - -export interface IFollowing { - avatar_url: string - html_url: string -} - -export interface IDataPayload { - [key: string]: IRepo[] | IFollower[] | IFollowing[] | undefined - repos?: IRepo[] - followers?: IFollower[] - following?: IFollowing[] -} - -export interface IDataAction { - payload?: IDataPayload - type: string -} - -export interface IData { - repos?: IRepoInfo[] - followers?: IUserLogin[] - following?: IUserLogin[] -} - -export interface IDataState { - data: IData -} - -export type TDataContext = { - state: IDataState - dispatch: React.Dispatch -} - -// components - -interface IHeaderProps { -} - -interface IHomeProps { - isLoading?: boolean -} - -interface ILayoutProps { - children?: ReactNode -} - -interface IActionState { - isLoading: boolean - errorMessage: string -} - -interface IComponentWithUserProp { - user: TAuthContext -} - -interface IComponentWithDataProp { - data: TDataContext -} - -interface ITableResourceProps extends IComponentWithUserProp, IComponentWithDataProp { - headers: React.ComponentType - name: "repos" | "followers" | "following" - row: React.ComponentType<{resource: T}> - title: string -} - -interface IRepoInfo { - html_url: string - full_name: string - updated_at: string -} diff --git a/examples/single-page-app/ui/src/App.tsx b/examples/single-page-app/ui/src/App.tsx deleted file mode 100644 index c5590ce55f8f..000000000000 --- a/examples/single-page-app/ui/src/App.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import {ChakraProvider, extendTheme} from '@chakra-ui/react' -import {createContext, useReducer} from 'react' -import {BrowserRouter as Router, Route, Routes} from "react-router-dom" - -import Auth from "./components/Auth" -import Home from "./components/Home" -import Login from "./components/Login" -import Logout from "./components/Logout" -import {TAuthContext, TDataContext} from "./@types/app" -import {dataInitialState, dataReducer, userInitialState, userReducer} from "./store/reducer" - -export const AuthContext = createContext(null) -export const DataContext = createContext(null) - -const theme = extendTheme({ - colors: { - primary: { - 500: '#000', - }, - }, -}) - -function App() { - const [userState, userDispatch] = useReducer(userReducer, userInitialState) - const [dataState, dataDispatch] = useReducer(dataReducer, dataInitialState) - return ( - - - - - - }/> - }/> - }/> - }/> - - - - - - ) -} - -export default App diff --git a/examples/single-page-app/ui/src/components/Auth.tsx b/examples/single-page-app/ui/src/components/Auth.tsx deleted file mode 100644 index 935f5519d919..000000000000 --- a/examples/single-page-app/ui/src/components/Auth.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import {useEffect, useContext} from "react" -import {Navigate} from "react-router-dom" -import {AuthContext} from "../App" -import {TAuthContext} from "../@types/app" -import Home from "./Home" - -export default function Auth() { - const {dispatch, state} = useContext(AuthContext) as TAuthContext - useEffect(() => { - if (!state.isLoggedIn) { - // We cannot login here as Envoy requires a request be made after - // succesful authentication in order to trigger the completion of the - // OAuth flow - dispatch({type: "RESET"}) - window.location.href = '/login' - } - }, [state, dispatch]) - if (state.isLoggedIn) { - return - } - return -} diff --git a/examples/single-page-app/ui/src/components/Header.tsx b/examples/single-page-app/ui/src/components/Header.tsx deleted file mode 100644 index 0bfb0b63052d..000000000000 --- a/examples/single-page-app/ui/src/components/Header.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import {useState} from "react" -import {CloseIcon, ChevronUpIcon} from '@chakra-ui/icons' -import {Box, Flex} from '@chakra-ui/react' -import {IHeaderProps} from "../@types/app" -import {UserMenu} from "./User" - -export const Header = (props: IHeaderProps) => { - const [show, setShow] = useState(false) - const toggleMenu = () => setShow(!show) - return ( - - - - - {show ? : } - - - - - - - - ) -} diff --git a/examples/single-page-app/ui/src/components/Home.tsx b/examples/single-page-app/ui/src/components/Home.tsx deleted file mode 100644 index 87b5e82f636f..000000000000 --- a/examples/single-page-app/ui/src/components/Home.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { - Tab, - TabList, - TabPanel, - TabPanels, - Tabs, - Text, -} from '@chakra-ui/react' -import {useContext} from "react" - -import {AuthContext} from "../App" -import { - IHomeProps, - TAuthContext} from "../@types/app" -import Layout from "./Layout" -import {RepoTableHeaders, RepoTr} from "./Repos" -import {RelatedUserTableHeaders, RelatedUserTr} from "./Users" -import {Resources} from "./Resources" - -export const Content = () => { - const {state: userState} = useContext(AuthContext) as TAuthContext - const {user} = userState - if (!userState.isLoggedIn || !user) { - return Login to query APIs - } - return ( - - - Repos - Followers - Following - - - - - - - - - - - - - - ) -} - -export default function Home (props: IHomeProps) { - return ( - - - - ) -} diff --git a/examples/single-page-app/ui/src/components/Layout.tsx b/examples/single-page-app/ui/src/components/Layout.tsx deleted file mode 100644 index ea30635f8593..000000000000 --- a/examples/single-page-app/ui/src/components/Layout.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import {Flex} from '@chakra-ui/react' -import {ILayoutProps} from "../@types/app" -import {Header} from "./Header" - -export default function Layout (props: ILayoutProps) { - return ( - -
- {props.children} - - ) -} diff --git a/examples/single-page-app/ui/src/components/Login.tsx b/examples/single-page-app/ui/src/components/Login.tsx deleted file mode 100644 index 7fa7b3c8d61d..000000000000 --- a/examples/single-page-app/ui/src/components/Login.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import {useToast} from '@chakra-ui/react' -import {useEffect, useContext} from "react" -import {Navigate} from "react-router-dom" -import {AuthContext} from "../App" -import {TAuthContext} from "../@types/app" -import Home from "./Home" - -/* -Note: Envoy's oAuth implementation requires that a page be requested *after* - a successful authorization/authentication. - - The consequence is that 2 pages are required to complete authentication - - this one and Auth.tsx which does a hard redirect here. - -*/ - -export default function Login() { - const {state, dispatch} = useContext(AuthContext) as TAuthContext - const {isLoggedIn} = state - const toast = useToast() - useEffect(() => { - const {authenticating, failed, isLoggedIn, proxy_url} = state - const fetchUser = async () => { - dispatch({type: "AUTH"}) - const response = await fetch(`${proxy_url}/user`) - const user = await response.json() - dispatch({ - type: "LOGIN", - payload: {user, isLoggedIn: true} - }) - } - if (!isLoggedIn && !authenticating && !failed) { - fetchUser().catch(error => { - dispatch({type: "ERROR"}) - toast({ - title: "Login failed.", - description: `${error.message}`, - status: "error", - duration: 9000, - isClosable: true, - }) - }) - } - }, [state, dispatch, toast]) - if (isLoggedIn) { - return - } - return -} diff --git a/examples/single-page-app/ui/src/components/Logout.tsx b/examples/single-page-app/ui/src/components/Logout.tsx deleted file mode 100644 index 26ebb5374899..000000000000 --- a/examples/single-page-app/ui/src/components/Logout.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import {Navigate} from "react-router-dom" - -export default function Logout() { - return ( - - ) -} diff --git a/examples/single-page-app/ui/src/components/Repos.tsx b/examples/single-page-app/ui/src/components/Repos.tsx deleted file mode 100644 index 93ea2b469288..000000000000 --- a/examples/single-page-app/ui/src/components/Repos.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - Flex, - Link, - Td, - Th, -} from '@chakra-ui/react' -import React from "react" - -import { - IRepoInfo, - IUserLogin} from "../@types/app" - - -export const RepoTableHeaders = () => { - return ( - <> - Repo - Updated - ) -} - -export const RepoTr: React.FC<{resource: IRepoInfo | IUserLogin}> = ({resource}) => { - const repo = resource as IRepoInfo - return ( - <> - - - - {repo.full_name} - - - - {repo.updated_at} - ) -} diff --git a/examples/single-page-app/ui/src/components/Resources.tsx b/examples/single-page-app/ui/src/components/Resources.tsx deleted file mode 100644 index 388e5c51ac89..000000000000 --- a/examples/single-page-app/ui/src/components/Resources.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { - Button, - Table, - TableCaption, - TableContainer, - Tbody, - Thead, - Tr, -} from '@chakra-ui/react' -import React from "react" - -import {withAuth, withData} from "../hoc" -import { - IActionState, - IDataPayload, - IRepoInfo, - ITableResourceProps, - IUserLogin} from "../@types/app" - -class BaseResources extends React.Component, IActionState> { - - constructor(props: ITableResourceProps) { - super(props) - this.state = {errorMessage: '', isLoading: false} - } - - render() { - const {data, name, headers: Headers, row: Row, title, user} = this.props - const rows = data.state.data?.[name] - const {user: userData} = user.state || {} - const {login} = userData || {} - - if (!login) { - return '' - } - - if (!rows || !Array.isArray(rows)) { - return - } - - return ( - <> - - - - {title} - - - - - - - {rows.map((resource, index: number) => ( - - - - ))} - -
-
- - ) - } - - updateResources = async () => { - const {data, name, user} = this.props - const {dispatch} = data - const {proxy_url, user: userData} = user.state - if (!userData) { - return - } - const {login} = userData - try { - const response = await fetch(`${proxy_url}/users/${login}/${name}`) - const resources = await response.json() - const payload: IDataPayload = {} - payload[name] = resources - dispatch({ - type: 'UPDATE', - payload, - }) - } catch (error) { - const e = error as Record<'message', string> - this.setState({ - isLoading: false, - errorMessage: `Sorry! Fetching ${name} failed\n${e.message}`, - }) - } - } -} - -const BaseResourcesWithProps = (props: ITableResourceProps) => { - return -} - -export const Resources = withAuth(withData(BaseResourcesWithProps as React.ComponentType)) diff --git a/examples/single-page-app/ui/src/components/User.tsx b/examples/single-page-app/ui/src/components/User.tsx deleted file mode 100644 index 29e6b13ac78f..000000000000 --- a/examples/single-page-app/ui/src/components/User.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import {useContext} from "react" -import {ChevronDownIcon} from '@chakra-ui/icons' -import { - Button, - Flex, - Image, - Menu, - MenuButton, - MenuList, - MenuItem, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Table, - TableCaption, - TableContainer, - Tbody, - Td, - Thead, - Th, - Tr, - Text, - useDisclosure, - useToast, -} from '@chakra-ui/react' -import {AuthContext} from "../App" -import {IUser, TAuthContext} from "../@types/app" -import {AuthProviders} from "../providers.tsx" - -export const UserMenu = () => { - const {state, dispatch} = useContext(AuthContext) as TAuthContext - const {isOpen, onOpen, onClose} = useDisclosure() - const {authenticating, isLoggedIn, provider, user} = state - const authProvider = AuthProviders[provider] - const toast = useToast() - const handleLogin = async () => { - // This is intercepted and redirected by Envoy - window.location.href = '/login' - } - const handleLogout = async () => { - const response = await fetch('/logout') - if (response.status === 200) { - await dispatch({ - type: "LOGOUT", - }) - } else { - toast({ - title: "Logout failed.", - description: `${response.statusText}`, - status: "error", - duration: 9000, - isClosable: true, - }) - } - } - const { - avatar_url = '...', - login = '...', - public_repos = '0', - followers = '0', - following = '0'} = user as IUser || {} - if (!isLoggedIn) { - const {icon: Icon, name: providerName} = authProvider - const loginText = authenticating ? 'Logging in' : `Login to ${providerName}`; - return ( - - handleLogin()}> - - - {loginText} - - - ) - } - return ( - - }> - - Avatar - {login} - - - - Info - - - - - - Avatar - {login} - - - - - - - Github user metrics - - - - - - - - - - - - - - - - - - - - -
metriccount
Repos{public_repos}
Followers{followers}
Following{following}
-
-
- - - -
-
- handleLogout()}>Logout -
-
) -} diff --git a/examples/single-page-app/ui/src/components/Users.tsx b/examples/single-page-app/ui/src/components/Users.tsx deleted file mode 100644 index d71eb8f8ae06..000000000000 --- a/examples/single-page-app/ui/src/components/Users.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { - Flex, - Image, - Link, - Td, - Th, -} from '@chakra-ui/react' -import React from "react" - -import { - IRepoInfo, - IUserLogin} from "../@types/app" - - -export const RelatedUserTableHeaders = () => { - return ( - <> - User - Full name - ) -} - -export const RelatedUserTr: React.FC<{resource: IRepoInfo | IUserLogin}> = ({resource}) => { - const user = resource as IUserLogin - return ( - <> - - - Avatar - - {user.login} - - - - - {user.name} - - ) -} diff --git a/examples/single-page-app/ui/src/hoc.tsx b/examples/single-page-app/ui/src/hoc.tsx deleted file mode 100644 index 1747d14e3535..000000000000 --- a/examples/single-page-app/ui/src/hoc.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, {useContext} from "react" - -import {AuthContext, DataContext} from "./App" -import { - IComponentWithDataProp, - IComponentWithUserProp, - TAuthContext, - TDataContext} from "./@types/app" - - -function getDisplayName(WrappedComponent: React.ComponentType): string { - return WrappedComponent.displayName || WrappedComponent.name || 'Component' -} - -export function withAuth(WrappedComponent: React.ComponentType>) { - function WithAuth>(props: TProps) { - return ( - ) - } - WithAuth.displayName = `WithAuth(${getDisplayName(WrappedComponent)})` - return WithAuth -} - -export function withData(WrappedComponent: React.ComponentType>) { - function WithData>(props: TProps) { - return ( - ) - } - WithData.displayName = `WithData(${getDisplayName(WrappedComponent)})` - return WithData -} diff --git a/examples/single-page-app/ui/src/main.tsx b/examples/single-page-app/ui/src/main.tsx deleted file mode 100644 index b176ead5a5a1..000000000000 --- a/examples/single-page-app/ui/src/main.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - -) diff --git a/examples/single-page-app/ui/src/myhub.tsx b/examples/single-page-app/ui/src/myhub.tsx deleted file mode 100644 index a84e788f4334..000000000000 --- a/examples/single-page-app/ui/src/myhub.tsx +++ /dev/null @@ -1,14 +0,0 @@ - -import {Image} from '@chakra-ui/react' - - -export const MyhubIcon = () => { - return ( - Myhub) -} diff --git a/examples/single-page-app/ui/src/providers.tsx b/examples/single-page-app/ui/src/providers.tsx deleted file mode 100644 index aa4983e9af05..000000000000 --- a/examples/single-page-app/ui/src/providers.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import GithubIcon from "mdi-react/GithubIcon" - -import {IAuthProviders} from "./@types/app" -import {MyhubIcon} from "./myhub" - - -export const AuthProviders: IAuthProviders = { - "myhub": { - "name": "Myhub", - "icon": MyhubIcon}, - "github": { - "name": "Github", - "icon": GithubIcon}} diff --git a/examples/single-page-app/ui/src/store/reducer/index.tsx b/examples/single-page-app/ui/src/store/reducer/index.tsx deleted file mode 100644 index 493e9ff5dd82..000000000000 --- a/examples/single-page-app/ui/src/store/reducer/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import {IAuthAction, IAuthState, IDataAction, IDataState} from "../../@types/app" - -export const userInitialState: IAuthState = { - authenticating: false, - failed: false, - isLoggedIn: JSON.parse(localStorage.getItem("isLoggedIn") || 'false'), - user: JSON.parse(localStorage.getItem("user") || 'null'), - proxy_url: `${import.meta.env.VITE_APP_API_URL}/hub`, - provider: import.meta.env.VITE_APP_AUTH_PROVIDER -} - -export const userReducer = (state: IAuthState, action: IAuthAction): IAuthState => { - switch (action.type) { - case "AUTH": { - return { - ...state, - authenticating: true - } - } - case "ERROR": { - return { - ...state, - authenticating: false, - failed: true - } - } - case "LOGIN": { - if (!action.payload) { - throw new Error('LOGIN called without payload') - } - localStorage.setItem("isLoggedIn", JSON.stringify(action.payload.isLoggedIn)) - localStorage.setItem("user", JSON.stringify(action.payload.user)) - return { - ...state, - authenticating: false, - isLoggedIn: action.payload.isLoggedIn, - user: action.payload.user - } - } - case "LOGOUT": { - localStorage.clear() - return { - ...state, - authenticating: false, - isLoggedIn: false, - user: null - } - } - case "RESET": { - return { - ...state, - failed: false - } - } - default: - return state - } -} - -export const dataInitialState: IDataState = { - data: JSON.parse(localStorage.getItem("data") || 'null'), -} - -export const dataReducer = (state: IDataState, action: IDataAction): IDataState => { - switch (action.type) { - case "UPDATE": { - if (!action.payload) { - throw new Error('UPDATE called without payload') - } - const data = { - ...JSON.parse(localStorage.getItem("data") || '{}'), - ...action.payload} - localStorage.setItem("data", JSON.stringify(data)) - return { - ...state, - data - } - } - default: - return state - } -} diff --git a/examples/single-page-app/ui/src/vite-env.d.ts b/examples/single-page-app/ui/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a006..000000000000 --- a/examples/single-page-app/ui/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/examples/single-page-app/ui/tsconfig.json b/examples/single-page-app/ui/tsconfig.json deleted file mode 100644 index a7fc6fbf23de..000000000000 --- a/examples/single-page-app/ui/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/examples/single-page-app/ui/tsconfig.node.json b/examples/single-page-app/ui/tsconfig.node.json deleted file mode 100644 index 42872c59f5b0..000000000000 --- a/examples/single-page-app/ui/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/examples/single-page-app/ui/vite.config.ts b/examples/single-page-app/ui/vite.config.ts deleted file mode 100644 index 3cd02eb20298..000000000000 --- a/examples/single-page-app/ui/vite.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {defineConfig} from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - server: { - host: '0.0.0.0', - }, -}) diff --git a/examples/single-page-app/ui/yarn.lock b/examples/single-page-app/ui/yarn.lock deleted file mode 100644 index 3eeb27064e4d..000000000000 --- a/examples/single-page-app/ui/yarn.lock +++ /dev/null @@ -1,4382 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== - dependencies: - "@babel/highlight" "^7.24.2" - picocolors "^1.0.0" - -"@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== - -"@babel/core@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" - integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.24.5" - "@babel/helpers" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" - integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== - dependencies: - "@babel/types" "^7.24.5" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== - dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.16.7": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-imports@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" - integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.24.3" - "@babel/helper-simple-access" "^7.24.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/helper-validator-identifier" "^7.24.5" - -"@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" - integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== - -"@babel/helper-simple-access@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz#50da5b72f58c16b07fbd992810be6049478e85ba" - integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-split-export-declaration@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" - integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== - dependencies: - "@babel/types" "^7.24.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-string-parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" - integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helpers@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" - integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.24.2": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" - integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.5" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" - integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== - -"@babel/parser@^7.24.0", "@babel/parser@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" - integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== - -"@babel/plugin-transform-react-jsx-self@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.5.tgz#22cc7572947895c8e4cd034462e65d8ecf857756" - integrity sha512-RtCJoUO2oYrYwFPtR1/jkoBEcFuI1ae9a9IMxeyAVa3a1Ap4AnxmyIKG2b2FaJKqkidw/0cxRbWN+HOs6ZWd1w== - dependencies: - "@babel/helper-plugin-utils" "^7.24.5" - -"@babel/plugin-transform-react-jsx-source@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz#a2dedb12b09532846721b5df99e52ef8dc3351d0" - integrity sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3": - version "7.23.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" - integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/template@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" - integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== - dependencies: - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/types" "^7.24.5" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" - integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.0", "@babel/types@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" - integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== - dependencies: - "@babel/helper-string-parser" "^7.24.1" - "@babel/helper-validator-identifier" "^7.24.5" - to-fast-properties "^2.0.0" - -"@chakra-ui/accordion@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-2.3.1.tgz#a326509e286a5c4e8478de9bc2b4b05017039e6b" - integrity sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag== - dependencies: - "@chakra-ui/descendant" "3.1.0" - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.1.0" - -"@chakra-ui/alert@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-2.2.2.tgz#aeba951d120c7c6e69d5f515a695ad6e4db43ffe" - integrity sha512-jHg4LYMRNOJH830ViLuicjb3F+v6iriE/2G5T+Sd0Hna04nukNJ1MxUmBPE+vI22me2dIflfelu2v9wdB6Pojw== - dependencies: - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/spinner" "2.1.0" - -"@chakra-ui/anatomy@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-2.2.2.tgz#2d0e14cba2534d92077ca28abf8c183b6e27897b" - integrity sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg== - -"@chakra-ui/avatar@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/avatar/-/avatar-2.3.0.tgz#f018a2714d1e3ba5970bcf66558887925fdfccf4" - integrity sha512-8gKSyLfygnaotbJbDMHDiJoF38OHXUYVme4gGxZ1fLnQEdPVEaIWfH+NndIjOM0z8S+YEFnT9KyGMUtvPrBk3g== - dependencies: - "@chakra-ui/image" "2.1.0" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/breadcrumb@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/breadcrumb/-/breadcrumb-2.2.0.tgz#751bc48498f3c403f97b5d9aae528ebfd405ef48" - integrity sha512-4cWCG24flYBxjruRi4RJREWTGF74L/KzI2CognAW/d/zWR0CjiScuJhf37Am3LFbCySP6WSoyBOtTIoTA4yLEA== - dependencies: - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/breakpoint-utils@2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz#750d3712668b69f6e8917b45915cee0e08688eed" - integrity sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/button@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/button/-/button-2.1.0.tgz#623ed32cc92fc8e52492923e9924791fc6f25447" - integrity sha512-95CplwlRKmmUXkdEp/21VkEWgnwcx2TOBG6NfYlsuLBDHSLlo5FKIiE2oSi4zXc4TLcopGcWPNcm/NDaSC5pvA== - dependencies: - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/spinner" "2.1.0" - -"@chakra-ui/card@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/card/-/card-2.2.0.tgz#b5e59dc51c171fced76ea76bf26088803b8bc184" - integrity sha512-xUB/k5MURj4CtPAhdSoXZidUbm8j3hci9vnc+eZJVDqhDOShNlD6QeniQNRPRys4lWAQLCbFcrwL29C8naDi6g== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/checkbox@2.3.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-2.3.2.tgz#4ecb14a2f57b7470d1a58542ca4691c3b105bfa1" - integrity sha512-85g38JIXMEv6M+AcyIGLh7igNtfpAN6KGQFYxY9tBj0eWvWk4NKQxvqqyVta0bSAyIl1rixNIIezNpNWk2iO4g== - dependencies: - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-callback-ref" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/visually-hidden" "2.2.0" - "@zag-js/focus-visible" "0.16.0" - -"@chakra-ui/clickable@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/clickable/-/clickable-2.1.0.tgz#800fa8d10cf45a41fc50a3df32c679a3ce1921c3" - integrity sha512-flRA/ClPUGPYabu+/GLREZVZr9j2uyyazCAUHAdrTUEdDYCr31SVGhgh7dgKdtq23bOvAQJpIJjw/0Bs0WvbXw== - dependencies: - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/close-button@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/close-button/-/close-button-2.1.1.tgz#995b245c56eb41465a71d8667840c238618a7b66" - integrity sha512-gnpENKOanKexswSVpVz7ojZEALl2x5qjLYNqSQGbxz+aP9sOXPfUS56ebyBrre7T7exuWGiFeRwnM0oVeGPaiw== - dependencies: - "@chakra-ui/icon" "3.2.0" - -"@chakra-ui/color-mode@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/color-mode/-/color-mode-2.2.0.tgz#828d47234c74ba2fb4c5dd63a63331aead20b9f6" - integrity sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg== - dependencies: - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - -"@chakra-ui/control-box@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/control-box/-/control-box-2.1.0.tgz#0f4586797b3154c02463bc5c106782e70c88f04f" - integrity sha512-gVrRDyXFdMd8E7rulL0SKeoljkLQiPITFnsyMO8EFHNZ+AHt5wK4LIguYVEq88APqAGZGfHFWXr79RYrNiE3Mg== - -"@chakra-ui/counter@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/counter/-/counter-2.1.0.tgz#e413a2f1093a18f847bb7aa240117fde788a59e6" - integrity sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw== - dependencies: - "@chakra-ui/number-utils" "2.0.7" - "@chakra-ui/react-use-callback-ref" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/css-reset@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-2.3.0.tgz#83e3160a9c2a12431cad0ee27ebfbf3aedc5c9c7" - integrity sha512-cQwwBy5O0jzvl0K7PLTLgp8ijqLPKyuEMiDXwYzl95seD3AoeuoCLyzZcJtVqaUZ573PiBdAbY/IlZcwDOItWg== - -"@chakra-ui/descendant@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/descendant/-/descendant-3.1.0.tgz#f3b80ed13ffc4bf1d615b3ed5541bd0905375cca" - integrity sha512-VxCIAir08g5w27klLyi7PVo8BxhW4tgU/lxQyujkmi4zx7hT9ZdrcQLAted/dAa+aSIZ14S1oV0Q9lGjsAdxUQ== - dependencies: - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - -"@chakra-ui/dom-utils@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/dom-utils/-/dom-utils-2.1.0.tgz#d15df89e458ef19756db04c7cfd084eb552454f0" - integrity sha512-ZmF2qRa1QZ0CMLU8M1zCfmw29DmPNtfjR9iTo74U5FPr3i1aoAh7fbJ4qAlZ197Xw9eAW28tvzQuoVWeL5C7fQ== - -"@chakra-ui/editable@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-3.1.0.tgz#065783c2e3389c3bb9ab0582cb50d38e1dc00fa1" - integrity sha512-j2JLrUL9wgg4YA6jLlbU88370eCRyor7DZQD9lzpY95tSOXpTljeg3uF9eOmDnCs6fxp3zDWIfkgMm/ExhcGTg== - dependencies: - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-callback-ref" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-focus-on-pointer-down" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/event-utils@2.0.8": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@chakra-ui/event-utils/-/event-utils-2.0.8.tgz#e6439ba200825a2f15d8f1973d267d1c00a6d1b4" - integrity sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw== - -"@chakra-ui/focus-lock@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/focus-lock/-/focus-lock-2.1.0.tgz#580e5450fe85356987b9a246abaff8333369c667" - integrity sha512-EmGx4PhWGjm4dpjRqM4Aa+rCWBxP+Rq8Uc/nAVnD4YVqkEhBkrPTpui2lnjsuxqNaZ24fIAZ10cF1hlpemte/w== - dependencies: - "@chakra-ui/dom-utils" "2.1.0" - react-focus-lock "^2.9.4" - -"@chakra-ui/form-control@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-2.2.0.tgz#69c771d6406ddac8ab357ae88446cc11827656a4" - integrity sha512-wehLC1t4fafCVJ2RvJQT2jyqsAwX7KymmiGqBu7nQoQz8ApTkGABWpo/QwDh3F/dBLrouHDoOvGmYTqft3Mirw== - dependencies: - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/hooks@2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-2.2.1.tgz#b86ce5eeaaab877ddcb11a50842d1227306ace28" - integrity sha512-RQbTnzl6b1tBjbDPf9zGRo9rf/pQMholsOudTxjy4i9GfTfz6kgp5ValGjQm2z7ng6Z31N1cnjZ1AlSzQ//ZfQ== - dependencies: - "@chakra-ui/react-utils" "2.0.12" - "@chakra-ui/utils" "2.0.15" - compute-scroll-into-view "3.0.3" - copy-to-clipboard "3.3.3" - -"@chakra-ui/icon@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-3.2.0.tgz#92b9454aa0d561b4994bcd6a1b3bb1fdd5c67bef" - integrity sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/icons@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/icons/-/icons-2.1.1.tgz#58ff0f9e703f2f4f89debd600ce4e438f43f9c9a" - integrity sha512-3p30hdo4LlRZTT5CwoAJq3G9fHI0wDc0pBaMHj4SUn0yomO+RcDRlzhdXqdr5cVnzax44sqXJVnf3oQG0eI+4g== - dependencies: - "@chakra-ui/icon" "3.2.0" - -"@chakra-ui/image@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/image/-/image-2.1.0.tgz#6c205f1ca148e3bf58345b0b5d4eb3d959eb9f87" - integrity sha512-bskumBYKLiLMySIWDGcz0+D9Th0jPvmX6xnRMs4o92tT3Od/bW26lahmV2a2Op2ItXeCmRMY+XxJH5Gy1i46VA== - dependencies: - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/input@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-2.1.2.tgz#0cad49ec372f8f21f2f4f1db365f34b9a708ff9d" - integrity sha512-GiBbb3EqAA8Ph43yGa6Mc+kUPjh4Spmxp1Pkelr8qtudpc3p2PJOOebLpd90mcqw8UePPa+l6YhhPtp6o0irhw== - dependencies: - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/object-utils" "2.1.0" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/layout@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-2.3.1.tgz#0601c5eb91555d24a7015a7c9d4e01fed2698557" - integrity sha512-nXuZ6WRbq0WdgnRgLw+QuxWAHuhDtVX8ElWqcTK+cSMFg/52eVP47czYBE5F35YhnoW2XBwfNoNgZ7+e8Z01Rg== - dependencies: - "@chakra-ui/breakpoint-utils" "2.0.8" - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/object-utils" "2.1.0" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/lazy-utils@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/lazy-utils/-/lazy-utils-2.0.5.tgz#363c3fa1d421362790b416ffa595acb835e1ae5b" - integrity sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg== - -"@chakra-ui/live-region@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/live-region/-/live-region-2.1.0.tgz#02b4b1d997075f19a7a9a87187e08c72e82ef0dd" - integrity sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw== - -"@chakra-ui/media-query@3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/media-query/-/media-query-3.3.0.tgz#40f9151dedb6a7af9df3be0474b59a799c92c619" - integrity sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g== - dependencies: - "@chakra-ui/breakpoint-utils" "2.0.8" - "@chakra-ui/react-env" "3.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/menu@2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-2.2.1.tgz#7d9810d435f6b40fa72ed867a33b88a1ef75073f" - integrity sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g== - dependencies: - "@chakra-ui/clickable" "2.1.0" - "@chakra-ui/descendant" "3.1.0" - "@chakra-ui/lazy-utils" "2.0.5" - "@chakra-ui/popper" "3.1.0" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-animation-state" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-disclosure" "2.1.0" - "@chakra-ui/react-use-focus-effect" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-outside-click" "2.2.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.1.0" - -"@chakra-ui/modal@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-2.3.1.tgz#524dc32b6b4f545b54ae531dbf6c74e1052ee794" - integrity sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ== - dependencies: - "@chakra-ui/close-button" "2.1.1" - "@chakra-ui/focus-lock" "2.1.0" - "@chakra-ui/portal" "2.1.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/transition" "2.1.0" - aria-hidden "^1.2.3" - react-remove-scroll "^2.5.6" - -"@chakra-ui/number-input@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-2.1.2.tgz#dda9095fba6a4b89212332db02831b94120da163" - integrity sha512-pfOdX02sqUN0qC2ysuvgVDiws7xZ20XDIlcNhva55Jgm095xjm8eVdIBfNm3SFbSUNxyXvLTW/YQanX74tKmuA== - dependencies: - "@chakra-ui/counter" "2.1.0" - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-callback-ref" "2.1.0" - "@chakra-ui/react-use-event-listener" "2.1.0" - "@chakra-ui/react-use-interval" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/number-utils@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz#aaee979ca2fb1923a0373a91619473811315db11" - integrity sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg== - -"@chakra-ui/object-utils@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz#a4ecf9cea92f1de09f5531f53ffdc41e0b19b6c3" - integrity sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ== - -"@chakra-ui/pin-input@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/pin-input/-/pin-input-2.1.0.tgz#61e6bbf909ec510634307b2861c4f1891a9f8d81" - integrity sha512-x4vBqLStDxJFMt+jdAHHS8jbh294O53CPQJoL4g228P513rHylV/uPscYUHrVJXRxsHfRztQO9k45jjTYaPRMw== - dependencies: - "@chakra-ui/descendant" "3.1.0" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/popover@2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-2.2.1.tgz#89cfd29817abcd204da570073c0f2b4d8072c3a3" - integrity sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg== - dependencies: - "@chakra-ui/close-button" "2.1.1" - "@chakra-ui/lazy-utils" "2.0.5" - "@chakra-ui/popper" "3.1.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-animation-state" "2.1.0" - "@chakra-ui/react-use-disclosure" "2.1.0" - "@chakra-ui/react-use-focus-effect" "2.1.0" - "@chakra-ui/react-use-focus-on-pointer-down" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/popper@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/popper/-/popper-3.1.0.tgz#92a9180c6894763af3b22a6003f9a9d958fe2659" - integrity sha512-ciDdpdYbeFG7og6/6J8lkTFxsSvwTdMLFkpVylAF6VNC22jssiWfquj2eyD4rJnzkRFPvIWJq8hvbfhsm+AjSg== - dependencies: - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@popperjs/core" "^2.9.3" - -"@chakra-ui/portal@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/portal/-/portal-2.1.0.tgz#9e7f57424d7041738b6563cac80134561080bd27" - integrity sha512-9q9KWf6SArEcIq1gGofNcFPSWEyl+MfJjEUg/un1SMlQjaROOh3zYr+6JAwvcORiX7tyHosnmWC3d3wI2aPSQg== - dependencies: - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - -"@chakra-ui/progress@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-2.2.0.tgz#67444ea9779631d7c8395b2c9c78e5634f994999" - integrity sha512-qUXuKbuhN60EzDD9mHR7B67D7p/ZqNS2Aze4Pbl1qGGZfulPW0PY8Rof32qDtttDQBkzQIzFGE8d9QpAemToIQ== - dependencies: - "@chakra-ui/react-context" "2.1.0" - -"@chakra-ui/provider@2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-2.4.2.tgz#92cb10b6a7df0720e3fa62716dc7cd872ae3ea3d" - integrity sha512-w0Tef5ZCJK1mlJorcSjItCSbyvVuqpvyWdxZiVQmE6fvSJR83wZof42ux0+sfWD+I7rHSfj+f9nzhNaEWClysw== - dependencies: - "@chakra-ui/css-reset" "2.3.0" - "@chakra-ui/portal" "2.1.0" - "@chakra-ui/react-env" "3.1.0" - "@chakra-ui/system" "2.6.2" - "@chakra-ui/utils" "2.0.15" - -"@chakra-ui/radio@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-2.1.2.tgz#66db19c61a2e628aaf5e727027f7c3b4006ea898" - integrity sha512-n10M46wJrMGbonaghvSRnZ9ToTv/q76Szz284gv4QUWvyljQACcGrXIONUnQ3BIwbOfkRqSk7Xl/JgZtVfll+w== - dependencies: - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@zag-js/focus-visible" "0.16.0" - -"@chakra-ui/react-children-utils@2.0.6": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-children-utils/-/react-children-utils-2.0.6.tgz#6c480c6a60678fcb75cb7d57107c7a79e5179b92" - integrity sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA== - -"@chakra-ui/react-context@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-context/-/react-context-2.1.0.tgz#4858be1d5ff1c8ac0a0ec088d93a3b7f1cbbff99" - integrity sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w== - -"@chakra-ui/react-env@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-env/-/react-env-3.1.0.tgz#7d3c1c05a501bb369524d9f3d38c9325eb16ab50" - integrity sha512-Vr96GV2LNBth3+IKzr/rq1IcnkXv+MLmwjQH6C8BRtn3sNskgDFD5vLkVXcEhagzZMCh8FR3V/bzZPojBOyNhw== - dependencies: - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - -"@chakra-ui/react-types@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-types/-/react-types-2.0.7.tgz#799c166a44882b23059c8f510eac9bd5d0869ac4" - integrity sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ== - -"@chakra-ui/react-use-animation-state@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.1.0.tgz#eab661fbafd96804fe867b0df0c27e78feefe6e2" - integrity sha512-CFZkQU3gmDBwhqy0vC1ryf90BVHxVN8cTLpSyCpdmExUEtSEInSCGMydj2fvn7QXsz/za8JNdO2xxgJwxpLMtg== - dependencies: - "@chakra-ui/dom-utils" "2.1.0" - "@chakra-ui/react-use-event-listener" "2.1.0" - -"@chakra-ui/react-use-callback-ref@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.1.0.tgz#a508085f4d9e7d84d4ceffdf5f41745c9ac451d7" - integrity sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ== - -"@chakra-ui/react-use-controllable-state@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.1.0.tgz#8fb6fa2f45d0c04173582ae8297e604ffdb9c7d9" - integrity sha512-QR/8fKNokxZUs4PfxjXuwl0fj/d71WPrmLJvEpCTkHjnzu7LnYvzoe2wB867IdooQJL0G1zBxl0Dq+6W1P3jpg== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-disclosure@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.1.0.tgz#90093eaf45db1bea7a6851dd0ce5cdb3eb66f90a" - integrity sha512-Ax4pmxA9LBGMyEZJhhUZobg9C0t3qFE4jVF1tGBsrLDcdBeLR9fwOogIPY9Hf0/wqSlAryAimICbr5hkpa5GSw== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-event-listener@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.1.0.tgz#afea2645bd9b38f754fc2b8eb858f9bb22385ded" - integrity sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-focus-effect@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.1.0.tgz#963fb790370dfadd51d12666ff2da60706f53a2a" - integrity sha512-xzVboNy7J64xveLcxTIJ3jv+lUJKDwRM7Szwn9tNzUIPD94O3qwjV7DDCUzN2490nSYDF4OBMt/wuDBtaR3kUQ== - dependencies: - "@chakra-ui/dom-utils" "2.1.0" - "@chakra-ui/react-use-event-listener" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - -"@chakra-ui/react-use-focus-on-pointer-down@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.1.0.tgz#2fbcf6bc7d06d97606747e231a908d5c387ca0cc" - integrity sha512-2jzrUZ+aiCG/cfanrolsnSMDykCAbv9EK/4iUyZno6BYb3vziucmvgKuoXbMPAzWNtwUwtuMhkby8rc61Ue+Lg== - dependencies: - "@chakra-ui/react-use-event-listener" "2.1.0" - -"@chakra-ui/react-use-interval@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-interval/-/react-use-interval-2.1.0.tgz#2602c097b3ab74b6644812e4f5efaad621218d98" - integrity sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-latest-ref@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-latest-ref/-/react-use-latest-ref-2.1.0.tgz#d1e926130102566ece1d39f8a48ed125e0c8441a" - integrity sha512-m0kxuIYqoYB0va9Z2aW4xP/5b7BzlDeWwyXCH6QpT2PpW3/281L3hLCm1G0eOUcdVlayqrQqOeD6Mglq+5/xoQ== - -"@chakra-ui/react-use-merge-refs@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.1.0.tgz#c0c233527abdbea9a1348269c192012205762314" - integrity sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ== - -"@chakra-ui/react-use-outside-click@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.2.0.tgz#5570b772a255f6f02b69e967127397c1b5fa3d3c" - integrity sha512-PNX+s/JEaMneijbgAM4iFL+f3m1ga9+6QK0E5Yh4s8KZJQ/bLwZzdhMz8J/+mL+XEXQ5J0N8ivZN28B82N1kNw== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-pan-event@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.1.0.tgz#51c21bc3c0e9e73d1faef5ea4f7e3c3d071a2758" - integrity sha512-xmL2qOHiXqfcj0q7ZK5s9UjTh4Gz0/gL9jcWPA6GVf+A0Od5imEDa/Vz+533yQKWiNSm1QGrIj0eJAokc7O4fg== - dependencies: - "@chakra-ui/event-utils" "2.0.8" - "@chakra-ui/react-use-latest-ref" "2.1.0" - framesync "6.1.2" - -"@chakra-ui/react-use-previous@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-previous/-/react-use-previous-2.1.0.tgz#f6046e6f7398b1e8d7e66ff7ebb8d61c92a2d3d0" - integrity sha512-pjxGwue1hX8AFcmjZ2XfrQtIJgqbTF3Qs1Dy3d1krC77dEsiCUbQ9GzOBfDc8pfd60DrB5N2tg5JyHbypqh0Sg== - -"@chakra-ui/react-use-safe-layout-effect@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.1.0.tgz#3a95f0ba6fd5d2d0aa14919160f2c825f13e686f" - integrity sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw== - -"@chakra-ui/react-use-size@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-size/-/react-use-size-2.1.0.tgz#fcf3070eaade8b4a84af8ce5341c4d5ca0a42bec" - integrity sha512-tbLqrQhbnqOjzTaMlYytp7wY8BW1JpL78iG7Ru1DlV4EWGiAmXFGvtnEt9HftU0NJ0aJyjgymkxfVGI55/1Z4A== - dependencies: - "@zag-js/element-size" "0.10.5" - -"@chakra-ui/react-use-timeout@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-timeout/-/react-use-timeout-2.1.0.tgz#24415f54267d7241a3c1d36a5cae4d472834cef7" - integrity sha512-cFN0sobKMM9hXUhyCofx3/Mjlzah6ADaEl/AXl5Y+GawB5rgedgAcu2ErAgarEkwvsKdP6c68CKjQ9dmTQlJxQ== - dependencies: - "@chakra-ui/react-use-callback-ref" "2.1.0" - -"@chakra-ui/react-use-update-effect@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.1.0.tgz#5c57cd1f50c2a6a8119e0f57f69510723d69884b" - integrity sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA== - -"@chakra-ui/react-utils@2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@chakra-ui/react-utils/-/react-utils-2.0.12.tgz#d6b773b9a5b2e51dce61f51ac8a0e9a0f534f479" - integrity sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw== - dependencies: - "@chakra-ui/utils" "2.0.15" - -"@chakra-ui/react@^2.8.2": - version "2.8.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-2.8.2.tgz#94d692fb35e4447748c5bfd73d8d38a746193c7d" - integrity sha512-Hn0moyxxyCDKuR9ywYpqgX8dvjqwu9ArwpIb9wHNYjnODETjLwazgNIliCVBRcJvysGRiV51U2/JtJVrpeCjUQ== - dependencies: - "@chakra-ui/accordion" "2.3.1" - "@chakra-ui/alert" "2.2.2" - "@chakra-ui/avatar" "2.3.0" - "@chakra-ui/breadcrumb" "2.2.0" - "@chakra-ui/button" "2.1.0" - "@chakra-ui/card" "2.2.0" - "@chakra-ui/checkbox" "2.3.2" - "@chakra-ui/close-button" "2.1.1" - "@chakra-ui/control-box" "2.1.0" - "@chakra-ui/counter" "2.1.0" - "@chakra-ui/css-reset" "2.3.0" - "@chakra-ui/editable" "3.1.0" - "@chakra-ui/focus-lock" "2.1.0" - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/hooks" "2.2.1" - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/image" "2.1.0" - "@chakra-ui/input" "2.1.2" - "@chakra-ui/layout" "2.3.1" - "@chakra-ui/live-region" "2.1.0" - "@chakra-ui/media-query" "3.3.0" - "@chakra-ui/menu" "2.2.1" - "@chakra-ui/modal" "2.3.1" - "@chakra-ui/number-input" "2.1.2" - "@chakra-ui/pin-input" "2.1.0" - "@chakra-ui/popover" "2.2.1" - "@chakra-ui/popper" "3.1.0" - "@chakra-ui/portal" "2.1.0" - "@chakra-ui/progress" "2.2.0" - "@chakra-ui/provider" "2.4.2" - "@chakra-ui/radio" "2.1.2" - "@chakra-ui/react-env" "3.1.0" - "@chakra-ui/select" "2.1.2" - "@chakra-ui/skeleton" "2.1.0" - "@chakra-ui/skip-nav" "2.1.0" - "@chakra-ui/slider" "2.1.0" - "@chakra-ui/spinner" "2.1.0" - "@chakra-ui/stat" "2.1.1" - "@chakra-ui/stepper" "2.3.1" - "@chakra-ui/styled-system" "2.9.2" - "@chakra-ui/switch" "2.1.2" - "@chakra-ui/system" "2.6.2" - "@chakra-ui/table" "2.1.0" - "@chakra-ui/tabs" "3.0.0" - "@chakra-ui/tag" "3.1.1" - "@chakra-ui/textarea" "2.1.2" - "@chakra-ui/theme" "3.3.1" - "@chakra-ui/theme-utils" "2.0.21" - "@chakra-ui/toast" "7.0.2" - "@chakra-ui/tooltip" "2.3.1" - "@chakra-ui/transition" "2.1.0" - "@chakra-ui/utils" "2.0.15" - "@chakra-ui/visually-hidden" "2.2.0" - -"@chakra-ui/select@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-2.1.2.tgz#f57d6cec0559373c32094fd4a5abd32855829264" - integrity sha512-ZwCb7LqKCVLJhru3DXvKXpZ7Pbu1TDZ7N0PdQ0Zj1oyVLJyrpef1u9HR5u0amOpqcH++Ugt0f5JSmirjNlctjA== - dependencies: - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/shared-utils@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz#cb2b49705e113853647f1822142619570feba081" - integrity sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q== - -"@chakra-ui/skeleton@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz#e3b25dd3afa330029d6d63be0f7cb8d44ad25531" - integrity sha512-JNRuMPpdZGd6zFVKjVQ0iusu3tXAdI29n4ZENYwAJEMf/fN0l12sVeirOxkJ7oEL0yOx2AgEYFSKdbcAgfUsAQ== - dependencies: - "@chakra-ui/media-query" "3.3.0" - "@chakra-ui/react-use-previous" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/skip-nav@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/skip-nav/-/skip-nav-2.1.0.tgz#cac27eecc6eded1e83c8f0cf7445d727739cb325" - integrity sha512-Hk+FG+vadBSH0/7hwp9LJnLjkO0RPGnx7gBJWI4/SpoJf3e4tZlWYtwGj0toYY4aGKl93jVghuwGbDBEMoHDug== - -"@chakra-ui/slider@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/slider/-/slider-2.1.0.tgz#1caeed18761ba2a390777418cc9389ba25e39bce" - integrity sha512-lUOBcLMCnFZiA/s2NONXhELJh6sY5WtbRykPtclGfynqqOo47lwWJx+VP7xaeuhDOPcWSSecWc9Y1BfPOCz9cQ== - dependencies: - "@chakra-ui/number-utils" "2.0.7" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-callback-ref" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-latest-ref" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-pan-event" "2.1.0" - "@chakra-ui/react-use-size" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - -"@chakra-ui/spinner@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/spinner/-/spinner-2.1.0.tgz#aa24a3d692c6ac90714e0f0f82c76c12c78c8e60" - integrity sha512-hczbnoXt+MMv/d3gE+hjQhmkzLiKuoTo42YhUG7Bs9OSv2lg1fZHW1fGNRFP3wTi6OIbD044U1P9HK+AOgFH3g== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/stat@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-2.1.1.tgz#a204ba915795345996a16c79794d84826d7dcc2d" - integrity sha512-LDn0d/LXQNbAn2KaR3F1zivsZCewY4Jsy1qShmfBMKwn6rI8yVlbvu6SiA3OpHS0FhxbsZxQI6HefEoIgtqY6Q== - dependencies: - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/stepper@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/stepper/-/stepper-2.3.1.tgz#a0a0b73e147f202ab4e51cae55dad45489cc89fd" - integrity sha512-ky77lZbW60zYkSXhYz7kbItUpAQfEdycT0Q4bkHLxfqbuiGMf8OmgZOQkOB9uM4v0zPwy2HXhe0vq4Dd0xa55Q== - dependencies: - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/styled-system@2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/styled-system/-/styled-system-2.9.2.tgz#898ab63da560a4a014f7b05fa7767e8c76da6d2f" - integrity sha512-To/Z92oHpIE+4nk11uVMWqo2GGRS86coeMmjxtpnErmWRdLcp1WVCVRAvn+ZwpLiNR+reWFr2FFqJRsREuZdAg== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - csstype "^3.1.2" - lodash.mergewith "4.6.2" - -"@chakra-ui/switch@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-2.1.2.tgz#f7c6878d8126bfac8fa3b939079f1017c21b7479" - integrity sha512-pgmi/CC+E1v31FcnQhsSGjJnOE2OcND4cKPyTE+0F+bmGm48Q/b5UmKD9Y+CmZsrt/7V3h8KNczowupfuBfIHA== - dependencies: - "@chakra-ui/checkbox" "2.3.2" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/system@2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-2.6.2.tgz#528ec955bd6a7f74da46470ee8225b1e2c80a78b" - integrity sha512-EGtpoEjLrUu4W1fHD+a62XR+hzC5YfsWm+6lO0Kybcga3yYEij9beegO0jZgug27V+Rf7vns95VPVP6mFd/DEQ== - dependencies: - "@chakra-ui/color-mode" "2.2.0" - "@chakra-ui/object-utils" "2.1.0" - "@chakra-ui/react-utils" "2.0.12" - "@chakra-ui/styled-system" "2.9.2" - "@chakra-ui/theme-utils" "2.0.21" - "@chakra-ui/utils" "2.0.15" - react-fast-compare "3.2.2" - -"@chakra-ui/table@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/table/-/table-2.1.0.tgz#20dce14c5e4d70dc7c6c0e87cce9b05907ff8c50" - integrity sha512-o5OrjoHCh5uCLdiUb0Oc0vq9rIAeHSIRScc2ExTC9Qg/uVZl2ygLrjToCaKfaaKl1oQexIeAcZDKvPG8tVkHyQ== - dependencies: - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/tabs@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-3.0.0.tgz#854c06880af26158d7c72881c4b5e0453f6c485d" - integrity sha512-6Mlclp8L9lqXmsGWF5q5gmemZXOiOYuh0SGT/7PgJVNPz3LXREXlXg2an4MBUD8W5oTkduCX+3KTMCwRrVrDYw== - dependencies: - "@chakra-ui/clickable" "2.1.0" - "@chakra-ui/descendant" "3.1.0" - "@chakra-ui/lazy-utils" "2.0.5" - "@chakra-ui/react-children-utils" "2.0.6" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-controllable-state" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/react-use-safe-layout-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/tag@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-3.1.1.tgz#d05284b6549a84d3a08e57eec57df3ad0eebd882" - integrity sha512-Bdel79Dv86Hnge2PKOU+t8H28nm/7Y3cKd4Kfk9k3lOpUh4+nkSGe58dhRzht59lEqa4N9waCgQiBdkydjvBXQ== - dependencies: - "@chakra-ui/icon" "3.2.0" - "@chakra-ui/react-context" "2.1.0" - -"@chakra-ui/textarea@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-2.1.2.tgz#30f8af0e233cec2dee79d527450c6586e7122eff" - integrity sha512-ip7tvklVCZUb2fOHDb23qPy/Fr2mzDOGdkrpbNi50hDCiV4hFX02jdQJdi3ydHZUyVgZVBKPOJ+lT9i7sKA2wA== - dependencies: - "@chakra-ui/form-control" "2.2.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/theme-tools@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-tools/-/theme-tools-2.1.2.tgz#913be05879cd816c546993ccb9ff7615f85ff69f" - integrity sha512-Qdj8ajF9kxY4gLrq7gA+Azp8CtFHGO9tWMN2wfF9aQNgG9AuMhPrUzMq9AMQ0MXiYcgNq/FD3eegB43nHVmXVA== - dependencies: - "@chakra-ui/anatomy" "2.2.2" - "@chakra-ui/shared-utils" "2.0.5" - color2k "^2.0.2" - -"@chakra-ui/theme-utils@2.0.21": - version "2.0.21" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme-utils/-/theme-utils-2.0.21.tgz#da7ed541a5241a8ed0384eb14f37fa9b998382cf" - integrity sha512-FjH5LJbT794r0+VSCXB3lT4aubI24bLLRWB+CuRKHijRvsOg717bRdUN/N1fEmEpFnRVrbewttWh/OQs0EWpWw== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/styled-system" "2.9.2" - "@chakra-ui/theme" "3.3.1" - lodash.mergewith "4.6.2" - -"@chakra-ui/theme@3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-3.3.1.tgz#75c6cd0b5c70c0aa955068274ee4780f299bd8a4" - integrity sha512-Hft/VaT8GYnItGCBbgWd75ICrIrIFrR7lVOhV/dQnqtfGqsVDlrztbSErvMkoPKt0UgAkd9/o44jmZ6X4U2nZQ== - dependencies: - "@chakra-ui/anatomy" "2.2.2" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/theme-tools" "2.1.2" - -"@chakra-ui/toast@7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-7.0.2.tgz#d1c396bbfced12e22b010899731fd8cc294d53ec" - integrity sha512-yvRP8jFKRs/YnkuE41BVTq9nB2v/KDRmje9u6dgDmE5+1bFt3bwjdf9gVbif4u5Ve7F7BGk5E093ARRVtvLvXA== - dependencies: - "@chakra-ui/alert" "2.2.2" - "@chakra-ui/close-button" "2.1.1" - "@chakra-ui/portal" "2.1.0" - "@chakra-ui/react-context" "2.1.0" - "@chakra-ui/react-use-timeout" "2.1.0" - "@chakra-ui/react-use-update-effect" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - "@chakra-ui/styled-system" "2.9.2" - "@chakra-ui/theme" "3.3.1" - -"@chakra-ui/tooltip@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@chakra-ui/tooltip/-/tooltip-2.3.1.tgz#29fb8508a37bb6b20ab8dbb32bca6cd59b098796" - integrity sha512-Rh39GBn/bL4kZpuEMPPRwYNnccRCL+w9OqamWHIB3Qboxs6h8cOyXfIdGxjo72lvhu1QI/a4KFqkM3St+WfC0A== - dependencies: - "@chakra-ui/dom-utils" "2.1.0" - "@chakra-ui/popper" "3.1.0" - "@chakra-ui/portal" "2.1.0" - "@chakra-ui/react-types" "2.0.7" - "@chakra-ui/react-use-disclosure" "2.1.0" - "@chakra-ui/react-use-event-listener" "2.1.0" - "@chakra-ui/react-use-merge-refs" "2.1.0" - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/transition@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/transition/-/transition-2.1.0.tgz#c8e95564f7ab356e78119780037bae5ad150c7b3" - integrity sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ== - dependencies: - "@chakra-ui/shared-utils" "2.0.5" - -"@chakra-ui/utils@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@chakra-ui/utils/-/utils-2.0.15.tgz#bd800b1cff30eb5a5e8c36fa039f49984b4c5e4a" - integrity sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA== - dependencies: - "@types/lodash.mergewith" "4.6.7" - css-box-model "1.2.1" - framesync "6.1.2" - lodash.mergewith "4.6.2" - -"@chakra-ui/visually-hidden@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz#9b0ecef8f01263ab808ba3bda7b36a0d91b4d5c1" - integrity sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ== - -"@emotion/babel-plugin@^11.12.0": - version "11.12.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" - integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.2" - "@emotion/memoize" "^0.9.0" - "@emotion/serialize" "^1.2.0" - babel-plugin-macros "^3.1.0" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.2.0" - -"@emotion/cache@^11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.0.tgz#8f51748b8116691dee0408b08ad758b8d246b097" - integrity sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g== - dependencies: - "@emotion/memoize" "^0.9.0" - "@emotion/sheet" "^1.4.0" - "@emotion/utils" "^1.4.0" - "@emotion/weak-memoize" "^0.4.0" - stylis "4.2.0" - -"@emotion/hash@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" - integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== - -"@emotion/is-prop-valid@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz#bd84ba972195e8a2d42462387581560ef780e4e2" - integrity sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ== - dependencies: - "@emotion/memoize" "^0.9.0" - -"@emotion/memoize@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" - integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== - -"@emotion/react@^11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.0.tgz#a9ebf827b98220255e5760dac89fa2d38ca7b43d" - integrity sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/cache" "^11.13.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" - "@emotion/weak-memoize" "^0.4.0" - hoist-non-react-statics "^3.3.1" - -"@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.0.tgz#e07cadfc967a4e7816e0c3ffaff4c6ce05cb598d" - integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA== - dependencies: - "@emotion/hash" "^0.9.2" - "@emotion/memoize" "^0.9.0" - "@emotion/unitless" "^0.9.0" - "@emotion/utils" "^1.4.0" - csstype "^3.0.2" - -"@emotion/sheet@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" - integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== - -"@emotion/styled@^11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" - integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/is-prop-valid" "^1.3.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" - -"@emotion/unitless@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.9.0.tgz#8e5548f072bd67b8271877e51c0f95c76a66cbe2" - integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ== - -"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" - integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== - -"@emotion/utils@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.0.tgz#262f1d02aaedb2ec91c83a0955dd47822ad5fbdd" - integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== - -"@emotion/weak-memoize@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" - integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== - -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== - -"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.0", "@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== - -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== - -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.22" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" - integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@popperjs/core@^2.9.3": - version "2.11.8" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" - integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== - -"@remix-run/router@1.18.0": - version "1.18.0" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.18.0.tgz#20b033d1f542a100c1d57cfd18ecf442d1784732" - integrity sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw== - -"@rollup/rollup-android-arm-eabi@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.1.tgz#88ba199f996e0000689130ed69e47df8b0dfbc70" - integrity sha512-4C4UERETjXpC4WpBXDbkgNVgHyWfG3B/NKY46e7w5H134UDOFqUJKpsLm0UYmuupW+aJmRgeScrDNfvZ5WV80A== - -"@rollup/rollup-android-arm64@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.1.tgz#c89a55670e1179ed7ba3db06cee0d7da7b3d35ce" - integrity sha512-TrTaFJ9pXgfXEiJKQ3yQRelpQFqgRzVR9it8DbeRzG0RX7mKUy0bqhCFsgevwXLJepQKTnLl95TnPGf9T9AMOA== - -"@rollup/rollup-darwin-arm64@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.1.tgz#52e3496fa66d761833df23a9b4860e517efc7d1d" - integrity sha512-fz7jN6ahTI3cKzDO2otQuybts5cyu0feymg0bjvYCBrZQ8tSgE8pc0sSNEuGvifrQJWiwx9F05BowihmLxeQKw== - -"@rollup/rollup-darwin-x64@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.1.tgz#7678922773a8b53d8b4b3c3cc3e77b65fc71b489" - integrity sha512-WTvdz7SLMlJpektdrnWRUN9C0N2qNHwNbWpNo0a3Tod3gb9leX+yrYdCeB7VV36OtoyiPAivl7/xZ3G1z5h20g== - -"@rollup/rollup-linux-arm-gnueabihf@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.1.tgz#69c3b896e3ee1c3487492323a02c2a3ae0d4b2e7" - integrity sha512-dBHQl+7wZzBYcIF6o4k2XkAfwP2ks1mYW2q/Gzv9n39uDcDiAGDqEyml08OdY0BIct0yLSPkDTqn4i6czpBLLw== - -"@rollup/rollup-linux-arm64-gnu@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.1.tgz#13353f0ab65f4add0241f97f7ccc640b3a2b5cf2" - integrity sha512-bur4JOxvYxfrAmocRJIW0SADs3QdEYK6TQ7dTNz6Z4/lySeu3Z1H/+tl0a4qDYv0bCdBpUYM0sYa/X+9ZqgfSQ== - -"@rollup/rollup-linux-arm64-musl@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.1.tgz#bf64eaa29b2b1e6bc9195f04bb30b2a4ffdc25ae" - integrity sha512-ssp77SjcDIUSoUyj7DU7/5iwM4ZEluY+N8umtCT9nBRs3u045t0KkW02LTyHouHDomnMXaXSZcCSr2bdMK63kA== - -"@rollup/rollup-linux-riscv64-gnu@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.1.tgz#ec05966a4ed1b3338c8842108353ac6d3443dc6a" - integrity sha512-Jv1DkIvwEPAb+v25/Unrnnq9BO3F5cbFPT821n3S5litkz+O5NuXuNhqtPx5KtcwOTtaqkTsO+IVzJOsxd11aQ== - -"@rollup/rollup-linux-s390x-gnu@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.1.tgz#c10a1f1522f0c9191ee45f677bd08763ddfdc039" - integrity sha512-U564BrhEfaNChdATQaEODtquCC7Ez+8Hxz1h5MAdMYj0AqD0GA9rHCpElajb/sQcaFL6NXmHc5O+7FXpWMa73Q== - -"@rollup/rollup-linux-x64-gnu@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.1.tgz#836f948b6efc53f05f57d1d9ba92e90d629b3f22" - integrity sha512-zGRDulLTeDemR8DFYyFIQ8kMP02xpUsX4IBikc7lwL9PrwR3gWmX2NopqiGlI2ZVWMl15qZeUjumTwpv18N7sQ== - -"@rollup/rollup-linux-x64-musl@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.1.tgz#07e0351cc18eeef026f903189d8312833cb6bd1f" - integrity sha512-VTk/MveyPdMFkYJJPCkYBw07KcTkGU2hLEyqYMsU4NjiOfzoaDTW9PWGRsNwiOA3qI0k/JQPjkl/4FCK1smskQ== - -"@rollup/rollup-win32-arm64-msvc@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.1.tgz#6f9359bbec6cb4a2c002642c63e3704b0b5e68b7" - integrity sha512-L+hX8Dtibb02r/OYCsp4sQQIi3ldZkFI0EUkMTDwRfFykXBPptoz/tuuGqEd3bThBSLRWPR6wsixDSgOx/U3Zw== - -"@rollup/rollup-win32-ia32-msvc@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.1.tgz#d6545a29ac9dd8b39a9161b87924f13471eb992e" - integrity sha512-+dI2jVPfM5A8zme8riEoNC7UKk0Lzc7jCj/U89cQIrOjrZTCWZl/+IXUeRT2rEZ5j25lnSA9G9H1Ob9azaF/KQ== - -"@rollup/rollup-win32-x64-msvc@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.1.tgz#d1b221daca9afca1885b91a311c6f4a04b0deeb5" - integrity sha512-YY1Exxo2viZ/O2dMHuwQvimJ0SqvL+OAWQLLY6rvXavgQKjhQUzn7nc1Dd29gjB5Fqi00nrBWctJBOyfVMIVxw== - -"@types/babel__core@^7.20.5": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" - integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== - dependencies: - "@babel/types" "^7.20.7" - -"@types/estree@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== - -"@types/json-schema@^7.0.12": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/lodash.mergewith@4.6.7": - version "4.6.7" - resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz#eaa65aa5872abdd282f271eae447b115b2757212" - integrity sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.202" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" - integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== - -"@types/parse-json@^4.0.0": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" - integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== - -"@types/prop-types@*": - version "15.7.11" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" - integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== - -"@types/react-dom@^18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^18.3.3": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/semver@^7.5.0": - version "7.5.6" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== - -"@typescript-eslint/eslint-plugin@^6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" - integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/type-utils" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" - natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^6.21.0", "@typescript-eslint/parser@^6.4.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" - integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== - dependencies: - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" - integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - -"@typescript-eslint/type-utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" - integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== - dependencies: - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" - integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== - -"@typescript-eslint/typescript-estree@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" - integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" - integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - semver "^7.5.4" - -"@typescript-eslint/visitor-keys@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" - integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== - dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" - -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -"@vitejs/plugin-react@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz#d0be6594051ded8957df555ff07a991fb618b48e" - integrity sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg== - dependencies: - "@babel/core" "^7.24.5" - "@babel/plugin-transform-react-jsx-self" "^7.24.5" - "@babel/plugin-transform-react-jsx-source" "^7.24.1" - "@types/babel__core" "^7.20.5" - react-refresh "^0.14.2" - -"@zag-js/dom-query@0.16.0": - version "0.16.0" - resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-0.16.0.tgz#bca46bcd78f78c900064478646d95f9781ed098e" - integrity sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ== - -"@zag-js/element-size@0.10.5": - version "0.10.5" - resolved "https://registry.yarnpkg.com/@zag-js/element-size/-/element-size-0.10.5.tgz#a24bad2eeb7e2c8709e32be5336e158e1a1a174f" - integrity sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w== - -"@zag-js/focus-visible@0.16.0": - version "0.16.0" - resolved "https://registry.yarnpkg.com/@zag-js/focus-visible/-/focus-visible-0.16.0.tgz#c9e53e3dbab0f2649d04a489bb379f5800f4f069" - integrity sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA== - dependencies: - "@zag-js/dom-query" "0.16.0" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -aria-hidden@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" - integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== - dependencies: - tslib "^2.0.0" - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-includes@^3.1.6, array-includes@^3.1.7, array-includes@^3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.4" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.findlast@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" - integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-shim-unscopables "^1.0.2" - -array.prototype.findlastindex@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" - integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.2.1" - -array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.tosorted@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" - integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.3" - es-errors "^1.3.0" - es-shim-unscopables "^1.0.2" - -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -babel-plugin-macros@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.22.2: - version "4.22.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" - integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== - dependencies: - caniuse-lite "^1.0.30001565" - electron-to-chromium "^1.4.601" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" - -builtin-modules@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" - integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== - -builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== - dependencies: - semver "^7.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" - integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== - dependencies: - function-bind "^1.1.2" - get-intrinsic "^1.2.1" - set-function-length "^1.1.1" - -call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -caniuse-lite@^1.0.30001565: - version "1.0.30001579" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz#45c065216110f46d6274311a4b3fcf6278e0852a" - integrity sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color2k@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.3.tgz#a771244f6b6285541c82aa65ff0a0c624046e533" - integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog== - -compute-scroll-into-view@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz#c418900a5c56e2b04b885b54995df164535962b1" - integrity sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^1.5.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -copy-to-clipboard@3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" - integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== - dependencies: - toggle-selection "^1.0.6" - -cosmiconfig@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -css-box-model@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" - integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== - dependencies: - tiny-invariant "^1.0.6" - -csstype@^3.0.2, csstype@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -define-data-property@^1.0.1, define-data-property@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" - integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== - dependencies: - get-intrinsic "^1.2.1" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - -define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -detect-node-es@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" - integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -electron-to-chromium@^1.4.601: - version "1.4.643" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.643.tgz#081a20c5534db91e66ef094f68624960f674768f" - integrity sha512-QHscvvS7gt155PtoRC0dR2ilhL8E9LHhfTQEq1uD5AL0524rBLAwpAREFH06f87/e45B9XkR6Ki5dbhbCsVEIg== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.5, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2, es-abstract@^1.23.3: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-abstract@^1.22.1: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.12" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.2.1, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-iterator-helpers@^1.0.19: - version "1.0.19" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" - integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.3" - es-errors "^1.3.0" - es-set-tostringtag "^2.0.3" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - globalthis "^1.0.3" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - internal-slot "^1.0.7" - iterator.prototype "^1.1.2" - safe-array-concat "^1.1.2" - -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== - dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" - -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -esbuild@^0.21.3: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== - optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-compat-utils@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz#f45e3b5ced4c746c127cf724fb074cd4e730d653" - integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== - -eslint-config-standard-with-typescript@^43.0.0: - version "43.0.1" - resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-43.0.1.tgz#977862d7d41b0e1f27f399137bbf7b2e017037ff" - integrity sha512-WfZ986+qzIzX6dcr4yGUyVb/l9N3Z8wPXCc5z/70fljs3UbWhhV+WxrfgsqMToRzuuyX9MqZ974pq2UPhDTOcA== - dependencies: - "@typescript-eslint/parser" "^6.4.0" - eslint-config-standard "17.1.0" - -eslint-config-standard@17.1.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" - integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== - -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== - dependencies: - debug "^3.2.7" - -eslint-plugin-es-x@^7.5.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz#d08d9cd155383e35156c48f736eb06561d07ba92" - integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== - dependencies: - "@eslint-community/eslint-utils" "^4.1.2" - "@eslint-community/regexpp" "^4.6.0" - eslint-compat-utils "^0.1.2" - -eslint-plugin-import@^2.25.2: - version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.15.0" - -"eslint-plugin-n@^15.0.0 || ^16.0.0 ": - version "16.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz#6a60a1a376870064c906742272074d5d0b412b0b" - integrity sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - builtins "^5.0.1" - eslint-plugin-es-x "^7.5.0" - get-tsconfig "^4.7.0" - globals "^13.24.0" - ignore "^5.2.4" - is-builtin-module "^3.2.1" - is-core-module "^2.12.1" - minimatch "^3.1.2" - resolve "^1.22.2" - semver "^7.5.3" - -eslint-plugin-promise@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz#acd3fd7d55cead7a10f92cf698f36c0aafcd717a" - integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== - -eslint-plugin-react-hooks@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" - integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== - -eslint-plugin-react-refresh@^0.4.9: - version "0.4.9" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.9.tgz#bf870372b353b12e1e6fb7fc41b282d9cbc8d93d" - integrity sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA== - -eslint-plugin-react@^7.35.0: - version "7.35.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz#00b1e4559896710e58af6358898f2ff917ea4c41" - integrity sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA== - dependencies: - array-includes "^3.1.8" - array.prototype.findlast "^1.2.5" - array.prototype.flatmap "^1.3.2" - array.prototype.tosorted "^1.1.4" - doctrine "^2.1.0" - es-iterator-helpers "^1.0.19" - estraverse "^5.3.0" - hasown "^2.0.2" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.8" - object.fromentries "^2.0.8" - object.values "^1.2.0" - prop-types "^15.8.1" - resolve "^2.0.0-next.5" - semver "^6.3.1" - string.prototype.matchall "^4.0.11" - string.prototype.repeat "^1.0.0" - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@^8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.9: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.16.0.tgz#83b9a9375692db77a822df081edb6a9cf6839320" - integrity sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" - -flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== - -focus-lock@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-1.0.0.tgz#2c50d8ce59d3d6608cda2672be9e65812459206c" - integrity sha512-a8Ge6cdKh9za/GZR/qtigTAk7SrGore56EFcoMshClsh7FLk1zwszc/ltuMfKhx56qeuyL/jWQ4J4axou0iJ9w== - dependencies: - tslib "^2.0.3" - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -framer-motion@^11.3.19: - version "11.3.19" - resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.3.19.tgz#7a2bd72ed1dd04a47d8ecb8444447cfc47c70984" - integrity sha512-+luuQdx4AsamyMcvzW7jUAJYIKvQs1KE7oHvKkW3eNzmo0S+3PSDWjBuQkuIP9WyneGnKGMLUSuHs8OP7jKpQg== - dependencies: - tslib "^2.4.0" - -framesync@6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/framesync/-/framesync-6.1.2.tgz#755eff2fb5b8f3b4d2b266dd18121b300aefea27" - integrity sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g== - dependencies: - tslib "2.4.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" - integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== - dependencies: - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-nonce@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" - integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - -get-tsconfig@^4.7.0: - version "4.7.2" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== - dependencies: - resolve-pkg-maps "^1.0.0" - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0, globals@^13.24.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== - dependencies: - get-intrinsic "^1.2.2" - -has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hoist-non-react-statics@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -ignore@^5.2.0, ignore@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" - integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== - -import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" - integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== - dependencies: - get-intrinsic "^1.2.2" - hasown "^2.0.0" - side-channel "^1.0.4" - -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-async-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" - integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== - dependencies: - has-tostringtag "^1.0.0" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-builtin-module@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" - integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== - dependencies: - builtin-modules "^3.3.0" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== - dependencies: - hasown "^2.0.0" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1, is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-finalizationregistry@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" - integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== - dependencies: - call-bind "^1.0.2" - -is-generator-function@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-set@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== - dependencies: - which-typed-array "^1.1.11" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -iterator.prototype@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" - integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== - dependencies: - define-properties "^1.2.1" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - reflect.getprototypeof "^1.0.4" - set-function-name "^2.0.1" - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.3.5" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" - integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== - dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - object.assign "^4.1.4" - object.values "^1.1.6" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.mergewith@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -mdi-react@^9.3.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/mdi-react/-/mdi-react-9.4.0.tgz#b1f886681084fc85dabbcbc31b39b518f5030ced" - integrity sha512-3McdJimHT2CO+bSDGgJ1SSmU6HvXLEwLdfFi3M/nQT4aauvVxIbIGTCI8eOCcPtkyVyVuZRcCZ7Gw0oaGldYLw== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1, object-inspect@^1.9.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4, object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" - integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -object.fromentries@^2.0.7, object.fromentries@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" - integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-object-atoms "^1.0.0" - -object.groupby@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" - integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - -object.values@^1.1.6, object.values@^1.1.7, object.values@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - -postcss@^8.4.39: - version "8.4.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.39.tgz#aa3c94998b61d3a9c259efa51db4b392e1bde0e3" - integrity sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.1" - source-map-js "^1.2.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prop-types@^15.6.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -react-clientside-effect@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" - integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== - dependencies: - "@babel/runtime" "^7.12.13" - -react-dom@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - -react-fast-compare@3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" - integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== - -react-focus-lock@^2.9.4: - version "2.9.7" - resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.7.tgz#778358691b55db38a9954a989341048bd4065935" - integrity sha512-EfhX040SELLqnQ9JftqsmQCG49iByg8F5X5m19Er+n371OaETZ35dlNPZrLOOTlnnwD4c2Zv0KDgabDTc7dPHw== - dependencies: - "@babel/runtime" "^7.0.0" - focus-lock "^1.0.0" - prop-types "^15.6.2" - react-clientside-effect "^1.2.6" - use-callback-ref "^1.3.0" - use-sidecar "^1.1.2" - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-refresh@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react-remove-scroll-bar@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" - integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== - dependencies: - react-style-singleton "^2.2.1" - tslib "^2.0.0" - -react-remove-scroll@^2.5.6: - version "2.5.7" - resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb" - integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA== - dependencies: - react-remove-scroll-bar "^2.3.4" - react-style-singleton "^2.2.1" - tslib "^2.1.0" - use-callback-ref "^1.3.0" - use-sidecar "^1.1.2" - -react-router-dom@^6.25.1: - version "6.25.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.25.1.tgz#b89f8d63fc8383ea4e89c44bf31c5843e1f7afa0" - integrity sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ== - dependencies: - "@remix-run/router" "1.18.0" - react-router "6.25.1" - -react-router@6.25.1: - version "6.25.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.25.1.tgz#70b4f1af79954cfcfd23f6ddf5c883e8c904203e" - integrity sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw== - dependencies: - "@remix-run/router" "1.18.0" - -react-style-singleton@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" - integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== - dependencies: - get-nonce "^1.0.0" - invariant "^2.2.4" - tslib "^2.0.0" - -react@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -reflect.getprototypeof@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" - integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - globalthis "^1.0.3" - which-builtin-type "^1.1.3" - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" - -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - -resolve@^1.19.0, resolve@^1.22.2, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^2.0.0-next.5: - version "2.0.0-next.5" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" - integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollup@^4.13.0: - version "4.13.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.1.tgz#5bd6d84eafd60280487085b8bf9c91679571005a" - integrity sha512-hFi+fU132IvJ2ZuihN56dwgpltpmLZHZWsx27rMCTZ2sYwrqlgL5sECGy1eeV2lAihD8EzChBVVhsXci0wD4Tg== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.13.1" - "@rollup/rollup-android-arm64" "4.13.1" - "@rollup/rollup-darwin-arm64" "4.13.1" - "@rollup/rollup-darwin-x64" "4.13.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.13.1" - "@rollup/rollup-linux-arm64-gnu" "4.13.1" - "@rollup/rollup-linux-arm64-musl" "4.13.1" - "@rollup/rollup-linux-riscv64-gnu" "4.13.1" - "@rollup/rollup-linux-s390x-gnu" "4.13.1" - "@rollup/rollup-linux-x64-gnu" "4.13.1" - "@rollup/rollup-linux-x64-musl" "4.13.1" - "@rollup/rollup-win32-arm64-msvc" "4.13.1" - "@rollup/rollup-win32-ia32-msvc" "4.13.1" - "@rollup/rollup-win32-x64-msvc" "4.13.1" - fsevents "~2.3.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-array-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.0.tgz#8d0cae9cb806d6d1c06e08ab13d847293ebe0692" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== - dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-regex-test@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.2.tgz#3ba32bdb3ea35f940ee87e5087c60ee786c3f6c5" - integrity sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ== - dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" - is-regex "^1.1.4" - -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.0.0, semver@^7.5.3, semver@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -set-function-length@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.0.tgz#2f81dc6c16c7059bda5ab7c82c11f03a515ed8e1" - integrity sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w== - dependencies: - define-data-property "^1.1.1" - function-bind "^1.1.2" - get-intrinsic "^1.2.2" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -set-function-name@^2.0.0, set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== - dependencies: - define-data-property "^1.0.1" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" - -set-function-name@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -side-channel@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - -source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -string.prototype.matchall@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" - integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.2" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.7" - regexp.prototype.flags "^1.5.2" - set-function-name "^2.0.2" - side-channel "^1.0.6" - -string.prototype.repeat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" - integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.5" - -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -stylis@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" - integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -tiny-invariant@^1.0.6: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toggle-selection@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" - integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== - -ts-api-utils@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" - integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== - -tsconfig-paths@^3.15.0: - version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typescript@*: - version "5.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" - integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -use-callback-ref@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0" - integrity sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ== - dependencies: - tslib "^2.0.0" - -use-sidecar@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" - integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== - dependencies: - detect-node-es "^1.1.0" - tslib "^2.0.0" - -vite@^5.3.5: - version "5.3.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.5.tgz#b847f846fb2b6cb6f6f4ed50a830186138cb83d8" - integrity sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA== - dependencies: - esbuild "^0.21.3" - postcss "^8.4.39" - rollup "^4.13.0" - optionalDependencies: - fsevents "~2.3.3" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-builtin-type@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== - dependencies: - function.prototype.name "^1.1.5" - has-tostringtag "^1.0.0" - is-async-function "^2.0.0" - is-date-object "^1.0.5" - is-finalizationregistry "^1.0.2" - is-generator-function "^1.0.10" - is-regex "^1.1.4" - is-weakref "^1.0.2" - isarray "^2.0.5" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - -which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/examples/single-page-app/verify.sh b/examples/single-page-app/verify.sh deleted file mode 100755 index 2e1cb87bd37d..000000000000 --- a/examples/single-page-app/verify.sh +++ /dev/null @@ -1,304 +0,0 @@ -#!/bin/bash -e - -# Note: This uses the pip version of yq, which is a simple -# wrapper taking jq args - not the separate package installed -# with eg snap - -export NAME=single-page-app -export PORT_DEV_PROXY="${SPA_PORT_DEV_PROXY:-11901}" -export PORT_PROXY="${SPA_PORT_PROXY:-11900}" -export PORT_MYHUB="${SPA_PORT_MYHUB:-11902}" -export MANUAL=true - - -BACKUP_FILES=( - "envoy.yml" -) - - -finally () { - rm -rf .local.ci - for file in "${BACKUP_FILES[@]}"; do - move_if_exists "${file}.bak" "${file}" - done -} - -export -f finally - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# As much of the logic is implemented in js, not everything can get tested, at least without using -# eg selenium or similar. -# Everything else should be tested. - - -EXPECTED_USER_JQ=$( -cat << 'EOF' -{"avatar_url": "http://localhost:\($port)/images/users/envoy.svg", - "followers": 3, - "following": 2, - "name": "Envoy Demo", - "login": "envoydemo", - "public_repos": 3} -EOF -) -EXPECTED_USER="$( - yq -c \ - --arg port "$PORT_MYHUB" \ - "$EXPECTED_USER_JQ" \ - < myhub/data.yml)" - -EXPECTED_REPOS_JQ=$( -cat << 'EOF' -.users.envoydemo.public_repos as $user_repos -| .repos as $repos -| $user_repos -| map({ - "html_url": "http://localhost:\($port)/envoydemo/\(.)", - "updated_at": $repos[.].updated_at, - "full_name": "envoydemo/\(.)"}) -EOF -) -EXPECTED_REPOS="$( - yq -c \ - --arg port "$PORT_MYHUB" \ - "$EXPECTED_REPOS_JQ" \ - < myhub/data.yml)" - -EXPECTED_FOLLOWERS_JQ=$( -cat << 'EOF' -.users.envoydemo.followers as $followers -| .users as $users -| $followers -| map({ - "avatar_url": "http://localhost:\($port)/images/users/\(.).png", - "name": $users[.].name, - "html_url": "http://localhost:\($port)/users/\(.)", - "login": .}) -EOF -) -EXPECTED_FOLLOWING="$( - yq -c \ - --arg port "$PORT_MYHUB" \ - "$EXPECTED_FOLLOWERS_JQ" \ - < myhub/data.yml)" - -EXPECTED_FOLLOWING_JQ=$( -cat << 'EOF' -.users.envoydemo.following as $following -| .users as $users -| $following -| map({ - "avatar_url": "http://localhost:\($port)/images/users/\(.).png", - "name": $users[.].name, - "html_url": "http://localhost:\($port)/users/\(.)", - "login": .}) -EOF -) -EXPECTED_FOLLOWING="$( - yq -c \ - --arg port "$PORT_MYHUB" \ - "$EXPECTED_FOLLOWING_JQ" \ - < myhub/data.yml)" - - -test_auth () { - local proxy_port - proxy_scheme=$1 - proxy_port=$2 - curl_args=() - if [[ "$proxy_scheme" == "https" ]]; then - curl_args=(-k) - fi - - run_log "Fetch the app page" - responds_with \ - "Envoy single page app example" \ - "${proxy_scheme}://localhost:${proxy_port}" \ - "${curl_args[@]}" - - run_log "Inititiate login" - responds_with_header \ - "HTTP/1.1 302 Found" \ - "${proxy_scheme}://localhost:${proxy_port}/login" \ - "${curl_args[@]}" - responds_with_header \ - "location: http://localhost:${PORT_MYHUB}/authorize?client_id=0123456789&redirect_uri=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Fauthorize&response_type=code&scope=user%3Aemail&state=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Flogin" \ - "${proxy_scheme}://localhost:${proxy_port}/login" \ - "${curl_args[@]}" - - run_log "Fetch the myhub authorization page" - responds_with_header \ - "HTTP/1.1 302 Found" \ - "http://localhost:${PORT_MYHUB}/authorize?client_id=0123456789&redirect_uri=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Fauthorize&response_type=code&scope=user%3Aemail&state=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Flogin" \ - "${curl_args[@]}" - responds_with_header \ - "Location: ${proxy_scheme}://localhost:${proxy_port}/authorize?code=" \ - "http://localhost:${PORT_MYHUB}/authorize?client_id=0123456789&redirect_uri=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Fauthorize&response_type=code&scope=user%3Aemail&state=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Flogin" \ - "${curl_args[@]}" - - run_log "Return to the app and receive creds" - CODE=$(_curl "${curl_args[@]}" --head "http://localhost:${PORT_MYHUB}/authorize?client_id=0123456789&redirect_uri=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Fauthorize&response_type=code&scope=user%3Aemail&state=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Flogin" | grep Location | cut -d= -f2 | cut -d\& -f1) - RESPONSE=$(_curl "${curl_args[@]}" --head "${proxy_scheme}://localhost:${proxy_port}/authorize?code=$CODE&state=${proxy_scheme}%3A%2F%2Flocalhost%3A${proxy_port}%2Flogin") - echo "$RESPONSE" | grep "HTTP/1.1 302 Found" - echo "$RESPONSE" | grep "location: ${proxy_scheme}://localhost:${proxy_port}/login" - echo "$RESPONSE" | grep "set-cookie: OauthHMAC=" - echo "$RESPONSE" | grep "set-cookie: OauthExpires=" - echo "$RESPONSE" | grep "set-cookie: BearerToken=" - - HMAC=$(echo "$RESPONSE" | grep "set-cookie: OauthHMAC=" | cut -d' ' -f2-) - OAUTH_EXPIRES=$(echo "$RESPONSE" | grep "set-cookie: OauthExpires=" | cut -d' ' -f2-) - TOKEN=$(echo "$RESPONSE" | grep "set-cookie: BearerToken=" | cut -d' ' -f2-) - COOKIES=( - --cookie "$HMAC" - --cookie "$OAUTH_EXPIRES" - --cookie "$TOKEN") - - endpoints=( - "Fetch user object|${EXPECTED_USER}|/hub/user" - "Fetch repos|${EXPECTED_REPOS}|/hub/users/envoydemo/repos" - "Fetch followers|${EXPECTED_FOLLOWERS}|/hub/users/envoydemo/followers" - "Fetch following|${EXPECTED_FOLLOWING}|/hub/users/envoydemo/following" - ) - - for endpoint in "${endpoints[@]}"; do - IFS='|' read -r log_message expected_response path <<< "$endpoint" - run_log "$log_message" - responds_with \ - "$expected_response" \ - "${proxy_scheme}://localhost:${proxy_port}${path}" \ - "${COOKIES[@]}" \ - "${curl_args[@]}" - done - - run_log "Log out of Myhub" - RESPONSE=$(_curl "${curl_args[@]}" --head "${proxy_scheme}://localhost:${proxy_port}/logout") - echo "$RESPONSE" | grep "HTTP/1.1 302 Found" - echo "$RESPONSE" | grep "location: ${proxy_scheme}://localhost:${proxy_port}/" - echo "$RESPONSE" | grep "set-cookie: OauthHMAC=deleted" - echo "$RESPONSE" | grep "set-cookie: BearerToken=deleted" -} - -get_js () { - _curl -k "https://localhost:${PORT_PROXY}" \ - | grep "assets/index" \ - | grep -oP '' \ - | grep -oP '/assets/[^"]+' \ - | sed 's/\/assets\///;s/".*//' -} - -run_log "Adjust environment for CI" -# This is specific to verify.sh script and so slightly adjust from docs. -rm -rf .local.ci -mkdir -p .local.ci -cp -a ui .local.ci/ -export UI_PATH=./.local.ci/ui -for file in "${BACKUP_FILES[@]}"; do - cp -a "${file}" "${file}.bak" -done -echo "VITE_APP_API_URL=https://localhost:${PORT_PROXY}" > ui/.env.production.local -echo "VITE_APP_API_URL=http://localhost:${PORT_DEV_PROXY}" > ui/.env.development.local -sed -i "s/localhost:7000/localhost:${PORT_MYHUB}/g" envoy.yml -export UID - -run_log "Generate an HMAC secret" -cp -a secrets/ .local.ci/ -export SECRETS_PATH=./.local.ci/secrets/ -HMAC_SECRET=$(echo "MY_HMAC_SECRET" | mkpasswd -s) -export HMAC_SECRET -envsubst < hmac-secret.tmpl.yml > .local.ci/secrets/hmac-secret.yml - -run_log "Start servers" -bring_up_example - -test_auth http "${PORT_DEV_PROXY}" - -run_log "Live reload dev app" -sed -i s/Envoy\ single\ page\ app\ example/CUSTOM\ APP/g .local.ci/ui/index.html -responds_with \ - "CUSTOM APP" \ - "http://localhost:${PORT_DEV_PROXY}" - -run_log "Run yarn lint" -docker compose run --rm ui yarn lint - -run_log "Build the production app" -mkdir -p .local.ci/production -cp -a xds .local.ci/production -cp -a ui/index.html .local.ci/ui/ -export XDS_PATH=./.local.ci/production/xds -docker compose up --build -d envoy -docker compose run --rm ui build.sh - -run_log "Check the created routes" -jq '.resources[0].filter_chains[0].filters[0].typed_config.route_config.virtual_hosts[0].routes' < .local.ci/production/xds/lds.yml - -test_auth https "${PORT_PROXY}" - -current_js=$(get_js) - -run_log "Ensure assets are served with compression" -responds_with_header \ - "content-encoding: gzip" \ - "https://localhost:${PORT_PROXY}/assets/${current_js}" \ - -k -i -H "Accept-Encoding: gzip" - -run_log "Rebuild production app" -sed -i s/Login\ to\ query\ APIs/LOGIN\ NOW/g .local.ci/ui/src/components/Home.tsx -docker compose run --rm ui build.sh -wait_for 5 \ - bash -c "\ - responds_without \ - \"$current_js\" \ - \"https://localhost:${PORT_PROXY}\" \ - \"-k\"" -responds_with \ - "Envoy single page app example" \ - "https://localhost:${PORT_PROXY}" \ - -k - -run_log "Update Envoy's configuration to use Github" -export TOKEN_SECRET=ZZZ -envsubst < token-secret.tmpl.yml > .local.ci/secrets/github-token-secret.yml -GITHUB_PROVIDED_CLIENT_ID=XXX -cp -a envoy.yml .local.ci/ -sed -i "s@cluster:\ hub@cluster:\ github@g" .local.ci/envoy.yml -sed -i "s@client_id:\ \"0123456789\"@client_id:\ \"$GITHUB_PROVIDED_CLIENT_ID\"@g" .local.ci/envoy.yml -sed -i "s@authorization_endpoint:\ http://localhost:${PORT_MYHUB}/authorize@authorization_endpoint:\ https://github.com/login/oauth/authorize@g" .local.ci/envoy.yml -sed -i "s@uri:\ http://myhub:${PORT_MYHUB}/authenticate@uri:\ https://github.com/login/oauth/access_token@g" .local.ci/envoy.yml -sed -i "s@path:\ /etc/envoy/secrets/myhub-token-secret.yml@path:\ /etc/envoy/secrets/github-token-secret.yml@g" .local.ci/envoy.yml -sed -i "s@host_rewrite_literal:\ api.myhub@host_rewrite_literal:\ api.github.com@g" .local.ci/envoy.yml -cat _github-clusters.yml >> .local.ci/envoy.yml - -run_log "Update the app configuration to use Github" -echo "VITE_APP_AUTH_PROVIDER=github" > .local.ci/ui/.env.local - -run_log "Rebuild the app and restart Envoy (Github)" -export ENVOY_CONFIG=.local.ci/envoy.yml -docker compose run --rm ui build.sh -docker compose up --build -d envoy - -run_log "Test dev app (Github)" -wait_for 5 \ - bash -c "\ - responds_with \ - \"Envoy single page app example\" \ - \"http://localhost:${PORT_DEV_PROXY}\"" -run_log "Inititiate dev login (Github)" -responds_with_header \ - "HTTP/1.1 302 Found" \ - "http://localhost:${PORT_DEV_PROXY}/login" -responds_with_header \ - "location: https://github.com/login/oauth/authorize?client_id=XXX&redirect_uri=http%3A%2F%2Flocalhost%3A${PORT_DEV_PROXY}%2Fauthorize&response_type=code&scope=user%3Aemail&state=http%3A%2F%2Flocalhost%3A${PORT_DEV_PROXY}%2Flogin" \ - "http://localhost:${PORT_DEV_PROXY}/login" - -run_log "Test production app (Github)" -responds_with \ - "Envoy single page app example" \ - "https://localhost:${PORT_PROXY}" \ - -k -responds_with_header \ - "location: https://github.com/login/oauth/authorize?client_id=XXX&redirect_uri=https%3A%2F%2Flocalhost%3A${PORT_PROXY}%2Fauthorize&response_type=code&scope=user%3Aemail&state=https%3A%2F%2Flocalhost%3A${PORT_PROXY}%2Flogin" \ - "https://localhost:${PORT_PROXY}/login" \ - -k diff --git a/examples/single-page-app/xds/lds.tmpl.yml b/examples/single-page-app/xds/lds.tmpl.yml deleted file mode 100644 index 298f054392b1..000000000000 --- a/examples/single-page-app/xds/lds.tmpl.yml +++ /dev/null @@ -1,28 +0,0 @@ -resources: -- "@type": type.googleapis.com/envoy.config.listener.v3.Listener - name: static_routes - address: - socket_address: - address: 0.0.0.0 - port_value: 10002 - access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StderrAccessLog - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: static_route - max_direct_response_body_size_bytes: 640000 - virtual_hosts: - - name: static_service - domains: ["*"] - routes: - http_filters: - - name: envoy.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/examples/skywalking/Dockerfile-elasticsearch b/examples/skywalking/Dockerfile-elasticsearch deleted file mode 100644 index 5f1c4ac29279..000000000000 --- a/examples/skywalking/Dockerfile-elasticsearch +++ /dev/null @@ -1 +0,0 @@ -FROM elasticsearch:8.14.3@sha256:1ddbb1ae0754278f3ab53edc24fcc5c790ebc2422cc47abea760b24abee2d88a diff --git a/examples/skywalking/Dockerfile-skywalking-oap b/examples/skywalking/Dockerfile-skywalking-oap deleted file mode 100644 index 74f1a6bbd3d4..000000000000 --- a/examples/skywalking/Dockerfile-skywalking-oap +++ /dev/null @@ -1 +0,0 @@ -FROM apache/skywalking-oap-server:latest@sha256:9af311a030f2a106dceecffddef72038e8a7335b92e2c2bd3a30be5942d663ea diff --git a/examples/skywalking/Dockerfile-skywalking-ui b/examples/skywalking/Dockerfile-skywalking-ui deleted file mode 100644 index bcc776bd9b1e..000000000000 --- a/examples/skywalking/Dockerfile-skywalking-ui +++ /dev/null @@ -1 +0,0 @@ -FROM apache/skywalking-ui:latest@sha256:6e87fcdaa13ef3cac4d1fc482422987461c9d6b79b661f2fa80bf16a271022b8 diff --git a/examples/skywalking/README.md b/examples/skywalking/README.md deleted file mode 100644 index 24020c335c0a..000000000000 --- a/examples/skywalking/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/skywalking) diff --git a/examples/skywalking/_static/skywalking-services.png b/examples/skywalking/_static/skywalking-services.png deleted file mode 100644 index 901947fb1f14..000000000000 Binary files a/examples/skywalking/_static/skywalking-services.png and /dev/null differ diff --git a/examples/skywalking/_static/skywalking-topology.png b/examples/skywalking/_static/skywalking-topology.png deleted file mode 100644 index 2ea133f1cbc0..000000000000 Binary files a/examples/skywalking/_static/skywalking-topology.png and /dev/null differ diff --git a/examples/skywalking/_static/skywalking-trace.png b/examples/skywalking/_static/skywalking-trace.png deleted file mode 100644 index 1aeff3f24480..000000000000 Binary files a/examples/skywalking/_static/skywalking-trace.png and /dev/null differ diff --git a/examples/skywalking/docker-compose.yaml b/examples/skywalking/docker-compose.yaml deleted file mode 100644 index 0a32f7fe6c04..000000000000 --- a/examples/skywalking/docker-compose.yaml +++ /dev/null @@ -1,130 +0,0 @@ -services: - - envoy-front-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-front-proxy.yaml - depends_on: - skywalking-ui: - condition: service_healthy - envoy-1: - condition: service_started - envoy-2: - condition: service_started - ports: - - "${PORT_PROXY:-10000}:10000" - - envoy-1: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-1.yaml - depends_on: - skywalking-ui: - condition: service_healthy - service-1: - condition: service_healthy - envoy-2: - condition: service_started - - envoy-2: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-2.yaml - depends_on: - skywalking-ui: - condition: service_healthy - service-2: - condition: service_healthy - - service-1: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=1 - - service-2: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=2 - - # Skywalking components. - elasticsearch: - build: - context: . - dockerfile: Dockerfile-elasticsearch - healthcheck: - test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - environment: - discovery.type: single-node - ingest.geoip.downloader.enabled: "false" - - cluster.routing.allocation.disk.watermark.low: "${ES_WATERMARK_LOW:-85%}" - cluster.routing.allocation.disk.watermark.high: "${ES_WATERMARK_HIGH:-90%}" - cluster.routing.allocation.disk.watermark.flood_stage: "${ES_WATERMARK_FLOOD:-95%}" - cluster.routing.allocation.disk.watermark.flood_stage.frozen: "${ES_WATERMARK_FLOOD_FROZEN:-95%}" - cluster.routing.allocation.disk.watermark.flood_stage.frozen.max_headroom: "${ES_MAX_HEADROOM:-20GB}" - - # NB: This setting is for demo purposes only, you are strongly advised to configure - # Elasticsearch with security enabled - xpack.security.enabled: "false" - ulimits: - memlock: - soft: -1 - hard: -1 - - skywalking-oap: - build: - context: . - dockerfile: Dockerfile-skywalking-oap - depends_on: - elasticsearch: - condition: service_healthy - environment: - SW_HEALTH_CHECKER: default - SW_STORAGE: elasticsearch - SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200 - healthcheck: - test: - - CMD-SHELL - - /skywalking/bin/swctl health - interval: 10s - timeout: 120s - retries: 10 - start_period: 10s - restart: on-failure - - skywalking-ui: - build: - context: . - dockerfile: Dockerfile-skywalking-ui - healthcheck: - test: - - CMD-SHELL - - >- - curl --silent --fail http://localhost:8080/graphql -X POST -H "Content-Type:application/json" - -d "{ \"query\": \"query version { version }\"}" || exit 1 - interval: 5s - timeout: 10s - retries: 10 - start_period: 10s - depends_on: - skywalking-oap: - condition: service_healthy - ports: - - "${PORT_UI:-8080}:8080" - environment: - SW_OAP_ADDRESS: http://skywalking-oap:12800 - SW_HEALTH_CHECKER: default diff --git a/examples/skywalking/envoy-1.yaml b/examples/skywalking/envoy-1.yaml deleted file mode 100644 index 85a51019cba6..000000000000 --- a/examples/skywalking/envoy-1.yaml +++ /dev/null @@ -1,136 +0,0 @@ -# This proxy listens on 2 ports: -# -# 10000 -> routes to `service-1` -# 10001 -> routes to `envoy-2` - -# The `client_config` settings below are used by Skywalking to identify the proxy. - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.skywalking - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig - grpc_service: - envoy_grpc: - cluster_name: skywalking - timeout: 0.250s - client_config: - service_name: envoy-proxy-1 - instance_name: envoy-proxy-1-1 - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - start_child_span: true - route_config: - name: service1_route - virtual_hosts: - - name: service1 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster1 - decorator: - operation: routeToService1 - - address: - socket_address: - address: 0.0.0.0 - port_value: 10001 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.skywalking - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig - grpc_service: - envoy_grpc: - cluster_name: skywalking - timeout: 0.250s - client_config: - service_name: envoy-proxy-1 - instance_name: envoy-proxy-1-2 - codec_type: AUTO - stat_prefix: egress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - start_child_span: true - route_config: - name: envoy2_route - virtual_hosts: - - name: envoy2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2 - - clusters: - - name: service_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-1 - port_value: 8080 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-2 - port_value: 10000 - - name: skywalking - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: skywalking - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: skywalking-oap - port_value: 11800 diff --git a/examples/skywalking/envoy-2.yaml b/examples/skywalking/envoy-2.yaml deleted file mode 100644 index d37bc8cabef3..000000000000 --- a/examples/skywalking/envoy-2.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# This proxy listens on port 10000 and routes all queries to `service-2`. - -# The `client_config` setting below is used by Skywalking to identify the proxy. - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.skywalking - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig - grpc_service: - envoy_grpc: - cluster_name: skywalking - timeout: 0.250s - client_config: - service_name: envoy-proxy-2 - instance_name: envoy-proxy-2-0 - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - start_child_span: true - route_config: - name: service2_route - virtual_hosts: - - name: service2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster2 - decorator: - operation: routeToService2 - - clusters: - - name: service_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-2 - port_value: 8080 - - name: skywalking - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: skywalking - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: skywalking-oap - port_value: 11800 diff --git a/examples/skywalking/envoy-front-proxy.yaml b/examples/skywalking/envoy-front-proxy.yaml deleted file mode 100644 index 0b318ba00bc8..000000000000 --- a/examples/skywalking/envoy-front-proxy.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# This proxy listens on port 10000, and routes the following paths: -# -# /trace/1 -> routes to `envoy-1` on port 10000 -# /trace/2 -> routes to `envoy-1` on port 10001 (for onward routing to `envoy-2`) - -# The `client_config` setting below is used by Skywalking to identify the proxy. - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - generate_request_id: true - tracing: - provider: - name: envoy.tracers.skywalking - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig - grpc_service: - envoy_grpc: - cluster_name: skywalking - timeout: 0.250s - client_config: - service_name: envoy-proxy-front - instance_name: envoy-proxy-front - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - start_child_span: true - route_config: - name: proxy_routes - virtual_hosts: - - name: proxy - domains: - - "*" - routes: - - match: - prefix: "/trace/1" - route: - cluster: envoy_cluster1 - decorator: - operation: routeToEnvoy1 - - match: - prefix: "/trace/2" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2ViaEnvoy1 - - clusters: - - name: envoy_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10000 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10001 - - name: skywalking - type: STRICT_DNS - lb_policy: ROUND_ROBIN - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - explicit_http_config: - http2_protocol_options: {} - load_assignment: - cluster_name: skywalking - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: skywalking-oap - port_value: 11800 diff --git a/examples/skywalking/example.rst b/examples/skywalking/example.rst deleted file mode 100644 index d3c8baddc3d7..000000000000 --- a/examples/skywalking/example.rst +++ /dev/null @@ -1,131 +0,0 @@ -.. _install_sandboxes_skywalking: - -Skywalking tracing -================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -The Skywalking tracing sandbox demonstrates Envoy's :ref:`request tracing ` -capabilities using `Skywalking `_ as the tracing provider. - -In this example, 2 backend services are provided: - -- ``service-1`` -- ``service-2`` - -3 Envoy proxies are also provided to route requests to them: - -- ``envoy-front-proxy`` (:download:`envoy-front-proxy.yaml <_include/skywalking/envoy-front-proxy.yaml>`) -- ``envoy-1`` (:download:`envoy-1.yaml <_include/skywalking/envoy-1.yaml>`) -- ``envoy-2`` (:download:`envoy-2.yaml <_include/skywalking/envoy-2.yaml>`) - -Of these services, only the Envoy ``front-proxy`` service is exposed outside of the -:download:`composition <_include/skywalking/docker-compose.yaml>`, on port ``10000``. - -For ``service-1``, requests are routed based on the request path ``trace/1``, as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> ``service-1`` - -For ``service-2``, requests are routed based on the request path ``trace/2`` as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> Envoy(``envoy-2``) -> ``service-2`` - -All Envoy proxies are configured to collect request traces, as can be seen in their configurations, -propagating the spans generated by the Skywalking tracer to a Skywalking OAP cluster. - -Each span records the latency of upstream API calls as well as information -needed to correlate the span with other related spans (e.g., the trace ID). - -The Skywalking web UI for viewing the collected traces is available on port ``8080``. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/skywalking`` in the Envoy repository. - -To build this sandbox example, and start the example services run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/skywalking - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------- - skywalking_elasticsearch_1 /bin/tini -- /usr/local/bi ... Up (healthy) 9200/tcp, 9300/tcp - skywalking_envoy-1_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - skywalking_envoy-2_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - skywalking_envoy-front-proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp - skywalking_service-1_1 python3 /code/service.py Up (healthy) - skywalking_service-2_1 python3 /code/service.py Up (healthy) - skywalking_skywalking-oap_1 bash docker-entrypoint.sh Up (healthy) 11800/tcp, 1234/tcp, 12800/tcp - skywalking_skywalking-ui_1 bash docker-entrypoint.sh Up (healthy) 0.0.0.0:8080->8080/tcp,:::8080->8080/tcp - -Step 2: Make a request to ``service-1`` -*************************************** - -Now send a request to ``service-1``, by calling http://localhost:10000/trace/1. - -This will be routed via 2 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` - -.. code-block:: console - - $ curl localhost:10000/trace/1 - Hello from behind Envoy (service 1)! - -Step 3: Make a request to ``service-2`` -*************************************** - -Now send a request to ``service-2``, by calling http://localhost:10000/trace/2. - -This will be routed via all 3 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` -- ``envoy-2`` - -.. code-block:: console - - $ curl localhost:10000/trace/2 - Hello from behind Envoy (service 2)! - -Step 4: View the traces in Skywalking UI -**************************************** - -Point your browser to http://localhost:8080. - -You should see the Skywalking dashboard. - -You may need to wait a moment for the traces to be added, but clicking on ``General Service > Services``, you -should see the Envoy services listed. - -.. image:: /start/sandboxes/_include/skywalking/_static/skywalking-services.png - -From here you can explore the metrics and views that skywalking offers, such as the ``Topology``: - -.. image:: /start/sandboxes/_include/skywalking/_static/skywalking-topology.png - -You can also view tracing information for the requests that you made: - -.. image:: /start/sandboxes/_include/skywalking/_static/skywalking-trace.png - -.. seealso:: - - :ref:`Request tracing ` - Learn more about using Envoy's request tracing. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. - - `Apache SkyWalking `_ - SkyWalking observability analysis platform and application performance management system. diff --git a/examples/skywalking/verify.sh b/examples/skywalking/verify.sh deleted file mode 100755 index b115b7ca2d82..000000000000 --- a/examples/skywalking/verify.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -e - -export NAME=skywalking -export PORT_PROXY="${SKYWALKING_PORT_PROXY:-11910}" -export PORT_UI="${SKYWALKING_PORT_UI:-11911}" - -# NB: This allows ES to run in a low-resource environment, -# dont do this in a production environment. -export ES_MAX_HEADROOM=1GB -export ES_WATERMARK_FLOOD_FROZEN=99% -export ES_WATERMARK_FLOOD=99% -export ES_WATERMARK_HIGH=99% -export ES_WATERMARK_LOW=99% - - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Make a request to service-1" -responds_with \ - "Hello from behind Envoy (service 1)!" \ - "http://localhost:${PORT_PROXY}/trace/1" - -run_log "Make a request to service-2" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/trace/2" - -run_log "View the traces in Skywalking UI" -responds_with \ - "" \ - "http://localhost:${PORT_UI}" - -run_log "Test OAP Server" -responds_with \ - "getEndpoints" \ - "http://localhost:${PORT_UI}/graphql" \ - -X POST \ - -H "Content-Type:application/json" \ - -d "{ \"query\": \"query queryEndpoints(\$serviceId: ID!, \$keyword: String!) { - getEndpoints: searchEndpoint(serviceId: \$serviceId, keyword: \$keyword, limit: 100) { - key: id - label: name - } - }\", - \"variables\": { \"serviceId\": \"\", \"keyword\": \"\" } - }" - -responds_with \ - "currentTimestamp" \ - "http://localhost:${PORT_UI}/graphql" \ - -X POST \ - -H "Content-Type:application/json" \ - -d "{ \"query\": \"query queryOAPTimeInfo { - getTimeInfo { - timezone - currentTimestamp - } - }\", - \"variables\": {} - }" diff --git a/examples/tls-inspector/README.md b/examples/tls-inspector/README.md deleted file mode 100644 index cc93e98e5adf..000000000000 --- a/examples/tls-inspector/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/tls-inspector.html). diff --git a/examples/tls-inspector/docker-compose.yaml b/examples/tls-inspector/docker-compose.yaml deleted file mode 100644 index 162f846321bb..000000000000 --- a/examples/tls-inspector/docker-compose.yaml +++ /dev/null @@ -1,40 +0,0 @@ -services: - - tls-inspector: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - depends_on: - service-https-http2: - condition: service_started - service-https-http1.1: - condition: service_started - service-http: - condition: service_started - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_ADMIN:-12345}:12345" - - service-https-http2: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: service-https-http2 - environment: - - HTTP_PORT=0 - - service-https-http1.1: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: service-https-http1.1 - environment: - - HTTP_PORT=0 - - service-http: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: service-http - environment: - - HTTPS_PORT=0 diff --git a/examples/tls-inspector/envoy.yaml b/examples/tls-inspector/envoy.yaml deleted file mode 100644 index 75c5c52572ab..000000000000 --- a/examples/tls-inspector/envoy.yaml +++ /dev/null @@ -1,79 +0,0 @@ -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 12345 -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - listener_filters: - - name: "envoy.filters.listener.tls_inspector" - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector - filter_chains: - - filter_chain_match: - transport_protocol: tls - application_protocols: [h2] - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: service-https-http2 - stat_prefix: https_passthrough - - filter_chain_match: - transport_protocol: tls - application_protocols: [http/1.1] - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: service-https-http1.1 - stat_prefix: https_passthrough - - filter_chain_match: - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: service-http - stat_prefix: ingress_http - - clusters: - - name: service-https-http2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-https-http2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-https-http2 - port_value: 443 - - name: service-https-http1.1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-https-http1.1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-https-http1.1 - port_value: 443 - - name: service-http - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-http - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-http - port_value: 80 diff --git a/examples/tls-inspector/example.rst b/examples/tls-inspector/example.rst deleted file mode 100644 index 9944a426379b..000000000000 --- a/examples/tls-inspector/example.rst +++ /dev/null @@ -1,108 +0,0 @@ -.. _install_sandboxes_tls_inspector: - -TLS Inspector Listener Filter -============================= - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`jq ` - Parse ``json`` output from the upstream echo servers. - -This example demonstrates how the ``TLS`` inspector can be used to select ``FilterChains`` to -distribute the traffic between upstream clusters according to the matched ``transport_protocol`` and/or -``application_protocols``. - -It also demonstrates the admin statistics generated by the ``TLS`` inspector listener filter. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/tls-inspector`` in the Envoy repository, and bring up the services. - -This starts one proxy listening on ``localhost:10000``, and with an admin interface listening on port 12345. - -It also starts three upstream ``HTTP`` services that echo back received headers in ``json`` format. - -The first 2 services are ``HTTPS`` services listening on port ``443`` and the other has no ``TLS`` and listens on -port ``80``. - -.. code-block:: console - - $ pwd - envoy/examples/tls-inspector - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------------- - tls-inspector_service-http_1 docker-entrypoint.sh node ... Up - tls-inspector_service-https-http1.1_1 docker-entrypoint.sh node ... Up - tls-inspector_service-https-http2_1 docker-entrypoint.sh node ... Up - tls-inspector_tls-inspector_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp, 0.0.0.0:12345->12345/tcp - - -Step 2: Access services -*********************** - -Querying the service at port 10000 with a different HTTP version specified over TLS, or -with HTTP protocol without TLS, the requests will be handled by different upstream services. - -Query the proxy with ``HTTP1.1`` and ``TLS`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - $ curl -sk --http1.1 https://localhost:10000 | jq '.os.hostname' - "service-https-http1.1" - -The upstream ``service-https-http1.1`` handles the request. - -Query the proxy with ``HTTP2`` and ``TLS`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - $ curl -sk --http2 https://localhost:10000 | jq '.os.hostname' - "service-https-http2" - -The upstream ``service-https-http2`` handles the request. - -Query the proxy with no ``TLS`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - $ curl -sk http://localhost:10000 | jq '.os.hostname' - "service-http" - -The upstream ``service-http`` handles the request. Since TLS Inspector listener filter detects the -transport is plaintext, it will not set transport_protocol to ``TLS``. - -Step 3: View the admin statistics -********************************* - -TLS inspector has a statistics tree rooted at ``tls_inspector``, which can be extracted with the -admin access entrypoint configured. - -.. code-block:: console - - $ curl -sk http://localhost:12345/stats |grep tls_inspector - tls_inspector.alpn_found: 2 - tls_inspector.alpn_not_found: 0 - tls_inspector.client_hello_too_large: 0 - tls_inspector.connection_closed: 0 - tls_inspector.read_error: 0 - tls_inspector.sni_found: 2 - tls_inspector.sni_not_found: 0 - tls_inspector.tls_found: 2 - tls_inspector.tls_not_found: 1 - -Viewing the admin statistics we can see that ``TLS``, ``SNI`` and ``ALPN`` are all detected since -we access services twice via ``HTTP`` over ``TLS``. It also shows one ``tls_not_found`` from the -plaintext query. diff --git a/examples/tls-inspector/verify.sh b/examples/tls-inspector/verify.sh deleted file mode 100755 index 2fe113c82906..000000000000 --- a/examples/tls-inspector/verify.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -e - -export NAME=tls-inspector -export PORT_PROXY="${TLS_INSPECTOR_PORT_PROXY:-12010}" -export PORT_ADMIN="${TLS_INSPECTOR_PORT_ADMIN:-12011}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -wait_for 30 sh -c "curl -s http://localhost:${PORT_ADMIN}/stats | grep 'tls_inspector.alpn_found: 0'" - -run_log "Curl tls inspector: HTTPS -> HTTP/1.1" -curl -sk --http1.1 "https://localhost:${PORT_PROXY}" | jq '.os.hostname' | grep service-https-http1.1 - -run_log "Curl tls inspector: HTTPS -> HTTP/2" -curl -sk --http2 "https://localhost:${PORT_PROXY}" | jq '.os.hostname' | grep service-https-http2 - -run_log "Curl tls inspector: HTTP" -curl -s "http://localhost:${PORT_PROXY}" | jq '.os.hostname' | grep service-http - -run_log "Check stats of tls inspector" -curl -s "http://localhost:${PORT_ADMIN}/stats" | grep "tls_inspector.alpn_found: 2" -curl -s "http://localhost:${PORT_ADMIN}/stats" | grep "tls_inspector.sni_found: 2" -curl -s "http://localhost:${PORT_ADMIN}/stats" | grep "tls_inspector.tls_found: 2" -curl -s "http://localhost:${PORT_ADMIN}/stats" | grep "tls_inspector.tls_not_found: 1" diff --git a/examples/tls-sni/README.md b/examples/tls-sni/README.md deleted file mode 100644 index 8f43b19a059f..000000000000 --- a/examples/tls-sni/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/tls-sni.html). diff --git a/examples/tls-sni/docker-compose.yaml b/examples/tls-sni/docker-compose.yaml deleted file mode 100644 index 25fdfc74e9a9..000000000000 --- a/examples/tls-sni/docker-compose.yaml +++ /dev/null @@ -1,43 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-certs - ports: - - "${PORT_PROXY:-10000}:10000" - - proxy-client: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - target: envoy-certs - args: - ENVOY_CONFIG: envoy-client.yaml - ports: - - "${PORT_PROXY_CLIENT:-20000}:10000" - - http-upstream1: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: http-upstream1 - environment: - - HTTPS_PORT=0 - - http-upstream2: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: http-upstream2 - environment: - - HTTPS_PORT=0 - - https-upstream3: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: https-upstream3 - environment: - - HTTP_PORT=0 diff --git a/examples/tls-sni/envoy-client.yaml b/examples/tls-sni/envoy-client.yaml deleted file mode 100644 index 6ad6fae1caa3..000000000000 --- a/examples/tls-sni/envoy-client.yaml +++ /dev/null @@ -1,91 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/domain1" - route: - cluster: proxy-client-domain1 - - match: - prefix: "/domain2" - route: - cluster: proxy-client-domain2 - - match: - prefix: "/domain3" - route: - cluster: proxy-client-domain3 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: proxy-client-domain1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-client-domain1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: proxy - port_value: 10000 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: domain1.example.com - - - name: proxy-client-domain2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-client-domain2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: proxy - port_value: 10000 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: domain2.example.com - - - name: proxy-client-domain3 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-client-domain3 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: proxy - port_value: 10000 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext - sni: domain3.example.com diff --git a/examples/tls-sni/envoy.yaml b/examples/tls-sni/envoy.yaml deleted file mode 100644 index cbd488c99f22..000000000000 --- a/examples/tls-sni/envoy.yaml +++ /dev/null @@ -1,130 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - listener_filters: - - name: "envoy.filters.listener.tls_inspector" - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector - filter_chains: - - filter_chain_match: - server_names: - - domain1.example.com - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: proxy-domain1 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - - certificate_chain: - filename: certs/domain1.crt.pem - private_key: - filename: certs/domain1.key.pem - - - filter_chain_match: - server_names: - - domain2.example.com - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: proxy-domain2 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - - certificate_chain: - filename: certs/domain2.crt.pem - private_key: - filename: certs/domain2.key.pem - - - filter_chain_match: - server_names: - - domain3.example.com - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: proxy-domain3 - stat_prefix: ingress_domain3 - - clusters: - - name: proxy-domain1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-domain1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: http-upstream1 - port_value: 80 - - - name: proxy-domain2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-domain2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: http-upstream2 - port_value: 80 - - - name: proxy-domain3 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: proxy-domain3 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: https-upstream3 - port_value: 443 diff --git a/examples/tls-sni/example.rst b/examples/tls-sni/example.rst deleted file mode 100644 index 726f833af2ec..000000000000 --- a/examples/tls-sni/example.rst +++ /dev/null @@ -1,175 +0,0 @@ -.. _install_sandboxes_tls_sni: - -TLS Server name indication (``SNI``) -==================================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`jq ` - Parse ``json`` output from the upstream echo servers. - -This example demonstrates an Envoy proxy that listens on three ``TLS`` domains -on the same ``IP`` address. - -The first two domains (``domain1`` and ``domain2``) terminate the ``TLS`` and proxy -to upstream ``HTTP`` hosts. - -The other domain (``domain3``) is proxied unterminated, based on the ``SNI`` headers. - -It also demonstrates Envoy acting as a client proxy connecting to upstream ``SNI`` services. - -.. _install_sandboxes_tls_sni_step1: - -Step 1: Create keypairs for each of the domain endpoints -******************************************************** - -Change directory to ``examples/tls-sni`` in the Envoy repository. - -The example creates two Envoy ``TLS`` endpoints and they will require their own -keypairs. - -Create self-signed certificates for these endpoints as follows: - -.. code-block:: console - - $ pwd - envoy/examples/tls-sni - - $ mkdir -p certs - - $ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=domain1.example.com" \ - -keyout certs/domain1.key.pem \ - -out certs/domain1.crt.pem - Generating a RSA private key - .............+++++ - ...................+++++ - writing new private key to 'certs/domain1.key.pem' - ----- - - $ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=domain2.example.com" \ - -keyout certs/domain2.key.pem \ - -out certs/domain2.crt.pem - Generating a RSA private key - .............+++++ - ...................+++++ - writing new private key to 'certs/domain2.key.pem' - ----- - -.. warning:: - - ``SNI`` does *not* validate that the certificates presented are correct for the domain, or that they - were issued by a recognised certificate authority. - - See the :ref:`Securing Envoy quick start guide ` for more information about - :ref:`validating cerfificates `. - -.. _install_sandboxes_tls_sni_step2: - -Step 2: Start the containers -**************************** - -Build and start the containers. - -This starts two upstream ``HTTP`` containers listening on the internal Docker network on port ``80``, and -an upstream ``HTTPS`` service listening on internal port ``443`` - -In front of these is an Envoy proxy that listens on https://localhost:10000 and serves three ``SNI`` routed -``TLS`` domains: - -- ``domain1.example.com`` -- ``domain2.example.com`` -- ``domain3.example.com`` - -The first two domains use the keys and certificates :ref:`you created in step 1 ` to terminate ``TLS`` and -proxy to the two upstream ``HTTP`` servers. - -The third domain proxies to the upstream ``TLS`` server based on the requested ``SNI`` address, but does no ``TLS`` termination itself. - -The composition also starts an Envoy proxy client which listens on http://localhost:20000. - -The client proxy has no ``TLS`` termination but instead proxies three routed paths - -``/domain1``, ``/domain2`` and ``/domain3`` - to the ``SNI``-enabled proxy. - -.. code-block:: console - - $ pwd - envoy/examples/tls-sni - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ------------------------------------------------------------------------------------------- - tls-sni_http-upstream1_1 node ./index.js Up - tls-sni_http-upstream2_1 node ./index.js Up - tls-sni_http-upstream3_1 node ./index.js Up - tls-sni_proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - tls-sni_proxy-client_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:20000->10000/tcp - -Step 2: Query the ``SNI`` endpoints directly with curl -****************************************************** - -You can use curl to query the ``SNI``-routed ``HTTPS`` endpoints of the Envoy proxy directly. - -To do this you must explicitly tell curl to resolve the ``DNS`` for the endpoints correctly. - -Each endpoint should proxy to the respective ``http-upstream`` or ``https-upstream`` service. - -.. code-block:: console - - $ curl -sk --resolve domain1.example.com:10000:127.0.0.1 \ - https://domain1.example.com:10000 \ - | jq -r '.os.hostname' - http-upstream1 - - $ curl -sk --resolve domain2.example.com:10000:127.0.0.1 \ - https://domain2.example.com:10000 \ - | jq -r '.os.hostname' - http-upstream2 - - $ curl -sk --resolve domain3.example.com:10000:127.0.0.1 \ - https://domain3.example.com:10000 \ - | jq -r '.os.hostname' - https-upstream3 - -Step 3: Query the ``SNI`` endpoints via an Envoy proxy client -************************************************************* - -Next, query the Envoy proxy client using the routed paths. - -These route via the ``SNI`` proxy endpoints to the respective ``http-upstream`` or -``https-upstream`` services. - -.. code-block:: console - - $ curl -s http://localhost:20000/domain1 \ - | jq '.os.hostname' - http-upstream1 - - $ curl -s http://localhost:20000/domain2 \ - | jq '.os.hostname' - http-upstream2 - - $ curl -s http://localhost:20000/domain3 \ - | jq '.os.hostname' - https-upstream3 - -.. seealso:: - - :ref:`Securing Envoy quick start guide ` - Outline of key concepts for securing Envoy. - - :ref:`TLS sandbox ` - Sandbox featuring examples of how Envoy can be configured to make - use of encrypted connections using ``HTTP`` over ``TLS``. - - :ref:`Double proxy sandbox ` - An example of securing traffic between proxies with validation and - mutual authentication using ``mTLS`` with non-``HTTP`` traffic. diff --git a/examples/tls-sni/verify.sh b/examples/tls-sni/verify.sh deleted file mode 100755 index f615835b5ea1..000000000000 --- a/examples/tls-sni/verify.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e - -export NAME=tls-sni -export MANUAL=true -export PORT_PROXY="${TLS_SNI_PORT_PROXY:-12020}" -export PORT_PROXY_CLIENT="${TLS_SNI_PORT_PROXY_CLIENT:-12021}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -# TODO(phlax): remove openssl bug workaround when openssl/ubuntu are updated -# see #15555 for more info -touch ~/.rnd - -create_self_signed_certs () { - local domain="$1" - openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \ - -subj "/C=US/ST=CA/O=MyExample, Inc./CN=${domain}.example.com" \ - -keyout "certs/${domain}.key.pem" \ - -out "certs/${domain}.crt.pem" -} - -mkdir -p certs - -run_log "Create certificates for each of the services" -create_self_signed_certs domain1 -create_self_signed_certs domain2 - -bring_up_example - -run_log "Query domain1 with curl and tls/sni" -curl -sk --resolve "domain1.example.com:${PORT_PROXY}:127.0.0.1" \ - "https://domain1.example.com:${PORT_PROXY}" \ - | jq '.os.hostname' | grep http-upstream1 - -run_log "Query domain2 with curl and tls/sni" -curl -sk --resolve "domain2.example.com:${PORT_PROXY}:127.0.0.1" \ - "https://domain2.example.com:${PORT_PROXY}" \ - | jq '.os.hostname' | grep http-upstream2 - -run_log "Query domain3 with curl and tls/sni" -curl -sk --resolve "domain3.example.com:${PORT_PROXY}:127.0.0.1" \ - "https://domain3.example.com:${PORT_PROXY}" \ - | jq '.os.hostname' | grep https-upstream3 - -run_log "Query domain1 via Envoy sni client" -curl -s "http://localhost:${PORT_PROXY_CLIENT}/domain1" \ - | jq '.os.hostname' | grep http-upstream1 - -run_log "Query domain2 via Envoy sni client" -curl -s "http://localhost:${PORT_PROXY_CLIENT}/domain2" \ - | jq '.os.hostname' | grep http-upstream2 - -run_log "Query domain3 via Envoy sni client" -curl -s "http://localhost:${PORT_PROXY_CLIENT}/domain3" \ - | jq '.os.hostname' | grep https-upstream3 diff --git a/examples/tls/README.md b/examples/tls/README.md deleted file mode 100644 index 61d68e1757a7..000000000000 --- a/examples/tls/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/tls.html). diff --git a/examples/tls/docker-compose.yaml b/examples/tls/docker-compose.yaml deleted file mode 100644 index 3b58da76c8b4..000000000000 --- a/examples/tls/docker-compose.yaml +++ /dev/null @@ -1,53 +0,0 @@ -services: - - proxy-https-to-http: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-https-http.yaml - ports: - - "${PORT_PROXY0:-10000}:10000" - - proxy-https-to-https: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-https-https.yaml - ports: - - "${PORT_PROXY1:-10001}:10000" - - proxy-http-to-https: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-http-https.yaml - ports: - - "${PORT_PROXY2:-10002}:10000" - - proxy-https-passthrough: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-https-passthrough.yaml - ports: - - "${PORT_PROXY3:-10003}:10000" - - service-http: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: service-http - environment: - - HTTPS_PORT=0 - - service-https: - build: - context: . - dockerfile: ../shared/echo2/Dockerfile - hostname: service-https - environment: - - HTTP_PORT=0 diff --git a/examples/tls/envoy-http-https.yaml b/examples/tls/envoy-http-https.yaml deleted file mode 100644 index 66952f6075dc..000000000000 --- a/examples/tls/envoy-http-https.yaml +++ /dev/null @@ -1,46 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service-https - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service-https - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-https - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-https - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext diff --git a/examples/tls/envoy-https-http.yaml b/examples/tls/envoy-https-http.yaml deleted file mode 100644 index c6d1ba0bac76..000000000000 --- a/examples/tls/envoy-https-http.yaml +++ /dev/null @@ -1,106 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service-http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: service-http - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-http - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-http - port_value: 80 diff --git a/examples/tls/envoy-https-https.yaml b/examples/tls/envoy-https-https.yaml deleted file mode 100644 index 8501c1ead0f3..000000000000 --- a/examples/tls/envoy-https-https.yaml +++ /dev/null @@ -1,110 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service-https - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: service-https - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-https - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-https - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext diff --git a/examples/tls/envoy-https-passthrough.yaml b/examples/tls/envoy-https-passthrough.yaml deleted file mode 100644 index 8707204a5c41..000000000000 --- a/examples/tls/envoy-https-passthrough.yaml +++ /dev/null @@ -1,27 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: service-https - stat_prefix: https_passthrough - - clusters: - - name: service-https - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service-https - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-https - port_value: 443 diff --git a/examples/tls/example.rst b/examples/tls/example.rst deleted file mode 100644 index 39baf0f86735..000000000000 --- a/examples/tls/example.rst +++ /dev/null @@ -1,179 +0,0 @@ -.. _install_sandboxes_tls: - -Transport layer security (``TLS``) -================================== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`jq ` - Parse ``json`` output from the upstream echo servers. - -This example walks through some of the ways that Envoy can be configured to make -use of encrypted connections using ``HTTP`` over ``TLS``. - -It demonstrates a number of commonly used proxying and ``TLS`` termination patterns: - -- ``https`` -> ``http`` -- ``https`` -> ``https`` -- ``http`` -> ``https`` -- ``https`` passthrough - -To better understand the provided examples, and for a description of how ``TLS`` is -configured with Envoy, please see the :ref:`securing Envoy quick start guide `. - -.. warning:: - - For the sake of simplicity, the examples provided here do not authenticate any client certificates, - or validate any of the provided certificates. - - When using ``TLS``, you are strongly encouraged to :ref:`validate ` - all certificates wherever possible. - - You should also :ref:`authenticate clients ` - where you control both sides of the connection, or relevant protocols are available. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/tls`` in the Envoy repository. - -This starts four proxies listening on ``localhost`` ports ``10000-10003``. - -It also starts two upstream services, one ``HTTP`` and one ``HTTPS``, which echo back received headers -in ``json`` format. - -The upstream services listen on the internal Docker network on ports ``80`` and ``443`` respectively. - -.. code-block:: console - - $ pwd - envoy/examples/tls - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------- - tls_proxy-https-to-http_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - tls_proxy-https-to-https_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10001->10000/tcp - tls_proxy-http-to-https_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10002->10000/tcp - tls_proxy-https-passthrough_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10003->10000/tcp - tls_service-http_1 node ./index.js Up - tls_service-https_1 node ./index.js Up - -Step 2: Test proxying ``https`` -> ``http`` -******************************************* - -The Envoy proxy listening on https://localhost:10000 terminates ``HTTPS`` and proxies to the upstream ``HTTP`` service. - -The :download:`https -> http configuration <_include/tls/envoy-https-http.yaml>` adds a ``TLS`` -:ref:`transport_socket ` to the -:ref:`listener `. - -Querying the service at port ``10000`` you should see an ``x-forwarded-proto`` header of ``https`` has -been added: - -.. code-block:: console - - $ curl -sk https://localhost:10000 | jq -r '.headers["x-forwarded-proto"]' - https - -The upstream ``service-http`` handles the request. - -.. code-block:: console - - $ curl -sk https://localhost:10000 | jq -r '.os.hostname' - service-http - -Step 3: Test proxying ``https`` -> ``https`` -******************************************** - -The Envoy proxy listening on https://localhost:10001 terminates ``HTTPS`` and proxies to the upstream ``HTTPS`` service. - -The :download:`https -> https configuration <_include/tls/envoy-https-https.yaml>` adds a ``TLS`` -:ref:`transport_socket ` to both the -:ref:`listener ` and the -:ref:`cluster `. - -Querying the service at port ``10001`` you should see an ``x-forwarded-proto`` header of ``https`` has -been added: - -.. code-block:: console - - $ curl -sk https://localhost:10001 | jq -r '.headers["x-forwarded-proto"]' - https - -The upstream ``service-https`` handles the request. - -.. code-block:: console - - $ curl -sk https://localhost:10001 | jq -r '.os.hostname' - service-https - -Step 4: Test proxying ``http`` -> ``https`` -******************************************* - -The Envoy proxy listening on http://localhost:10002 terminates ``HTTP`` and proxies to the upstream ``HTTPS`` service. - -The :download:`http -> https configuration <_include/tls/envoy-http-https.yaml>` adds a ``TLS`` -:ref:`transport_socket ` to the -:ref:`cluster `. - -Querying the service at port ``10002`` you should see an ``x-forwarded-proto`` header of ``http`` has -been added: - -.. code-block:: console - - $ curl -s http://localhost:10002 | jq -r '.headers["x-forwarded-proto"]' - http - -The upstream ``service-https`` handles the request. - -.. code-block:: console - - $ curl -s http://localhost:10002 | jq -r '.os.hostname' - service-https - - -Step 5: Test proxying ``https`` passthrough -******************************************* - -The Envoy proxy listening on https://localhost:10003 proxies directly to the upstream ``HTTPS`` service which -does the ``TLS`` termination. - -The :download:`https passthrough configuration <_include/tls/envoy-https-passthrough.yaml>` requires no ``TLS`` -or ``HTTP`` setup, and instead uses a simple -:ref:`tcp_proxy `. - -Querying the service at port ``10003`` you should see that no ``x-forwarded-proto`` header has been -added: - -.. code-block:: console - - $ curl -sk https://localhost:10003 | jq -r '.headers["x-forwarded-proto"]' - null - -The upstream ``service-https`` handles the request. - -.. code-block:: console - - $ curl -sk https://localhost:10003 | jq -r '.os.hostname' - service-https - -.. seealso:: - - :ref:`Securing Envoy quick start guide ` - Outline of key concepts for securing Envoy. - - :ref:`TLS SNI sandbox ` - Example of using Envoy to serve multiple domains protected by TLS and - served from the same ``IP`` address. - - :ref:`Double proxy sandbox ` - An example of securing traffic between proxies with validation and - mutual authentication using ``mTLS`` with non-``HTTP`` traffic. diff --git a/examples/tls/verify.sh b/examples/tls/verify.sh deleted file mode 100755 index 46c4af01e2d4..000000000000 --- a/examples/tls/verify.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -e - -export NAME=tls -export PORT_PROXY0="${TLS_PORT_PROXY0:-12000}" -export PORT_PROXY1="${TLS_PORT_PROXY1:-12001}" -export PORT_PROXY2="${TLS_PORT_PROXY2:-12002}" -export PORT_PROXY3="${TLS_PORT_PROXY3:-12003}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test https -> http" -responds_with \ - '"x-forwarded-proto": "https",' \ - -k \ - "https://localhost:${PORT_PROXY0}" -curl -sk "https://localhost:${PORT_PROXY0}" | jq '.os.hostname' | grep '"service-http"' - -run_log "Test https -> https" -responds_with \ - '"x-forwarded-proto": "https",' \ - -k \ - "https://localhost:${PORT_PROXY1}" -curl -sk "https://localhost:${PORT_PROXY1}" | jq '.os.hostname' | grep '"service-https"' - -run_log "Test http -> https" -responds_with \ - '"x-forwarded-proto": "http",' \ - "http://localhost:${PORT_PROXY2}" -curl -s "http://localhost:${PORT_PROXY2}" | jq '.os.hostname' | grep '"service-https"' - -run_log "Test https passthrough" -responds_without \ - '"x-forwarded-proto"' \ - -k \ - "https://localhost:${PORT_PROXY3}" -curl -sk "https://localhost:${PORT_PROXY3}" | jq '.os.hostname' | grep '"service-https"' diff --git a/examples/udp/Dockerfile-udp b/examples/udp/Dockerfile-udp deleted file mode 100644 index 76a45d7ac5ad..000000000000 --- a/examples/udp/Dockerfile-udp +++ /dev/null @@ -1 +0,0 @@ -FROM mendhak/udp-listener@sha256:ecc2961447560372fd6660c6db4bcf7e70d61f37f1421b1f8c4c7647da7c0aca diff --git a/examples/udp/README.md b/examples/udp/README.md deleted file mode 100644 index 15afa0a3ff05..000000000000 --- a/examples/udp/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/udp.html). diff --git a/examples/udp/docker-compose.yaml b/examples/udp/docker-compose.yaml deleted file mode 100644 index 5189bd79f51f..000000000000 --- a/examples/udp/docker-compose.yaml +++ /dev/null @@ -1,14 +0,0 @@ -services: - - testing: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000/udp" - - "${PORT_ADMIN:-10001}:10001" - - service-udp: - build: - context: . - dockerfile: Dockerfile-udp diff --git a/examples/udp/envoy.yaml b/examples/udp/envoy.yaml deleted file mode 100644 index d6e402808953..000000000000 --- a/examples/udp/envoy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -static_resources: - listeners: - - name: listener_0 - address: - socket_address: - protocol: UDP - address: 0.0.0.0 - port_value: 10000 - listener_filters: - - name: envoy.filters.udp_listener.udp_proxy - typed_config: - '@type': type.googleapis.com/envoy.extensions.filters.udp.udp_proxy.v3.UdpProxyConfig - stat_prefix: service - matcher: - on_no_match: - action: - name: route - typed_config: - '@type': type.googleapis.com/envoy.extensions.filters.udp.udp_proxy.v3.Route - cluster: service_udp - - clusters: - - name: service_udp - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_udp - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-udp - port_value: 5005 - -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 10001 diff --git a/examples/udp/example.rst b/examples/udp/example.rst deleted file mode 100644 index 6248af717583..000000000000 --- a/examples/udp/example.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. _install_sandboxes_udp: - -User Datagram Protocol (``UDP``) -================================ - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - - :ref:`netcat ` - Used to send ``UDP`` packets. - -This sandbox provides a very simple example of Envoy proxying ``UDP``. - -It also demonstrates ``UDP`` traffic stats provided by the Envoy admin endpoint. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/udp`` in the Envoy repository. - -Start the Docker composition: - -.. code-block:: console - - $ pwd - envoy/examples/udp - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------- - udp_envoy-udp_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:10000->10000/udp, 0.0.0.0:10001->10001/tcp - udp_service-udp_1 python -u /udplistener.py Up 5005/tcp, 5005/udp - -Envoy should proxy ``UDP`` on port ``10000`` to an upstream server listening on port ``5005``. - -Envoy also provides an admin endpoint listening on port ``10001``. - -Step 2: Send some ``UDP`` messages -********************************** - -You can use ``netcat`` to send packets to the upstream server, proxied by Envoy: - -.. code-block:: console - - echo -n HELO | nc -4u -w1 127.0.0.1 10000 - echo -n OLEH | nc -4u -w1 127.0.0.1 10000 - -Step 3: Check the logs of the upstream ``UDP`` listener server -************************************************************** - -Checking the logs of the upstream server you should see the packets that you sent: - -.. code-block:: console - - $ docker compose logs service-udp - Attaching to udp_service-udp_1 - service-udp_1 | Listening on UDP port 5005 - service-udp_1 | HELO - service-udp_1 | OLEH - -Step 4: View the Envoy admin ``UDP`` stats -****************************************** - -You can view the ``UDP``-related stats provided by the Envoy admin endpoint. - -For example, to view the non-zero stats: - -.. code-block:: console - - $ curl -s http://127.0.0.1:10001/stats | grep udp | grep -v "\: 0" - cluster.service_udp.default.total_match_count: 1 - cluster.service_udp.max_host_weight: 1 - cluster.service_udp.membership_change: 1 - cluster.service_udp.membership_healthy: 1 - cluster.service_udp.membership_total: 1 - cluster.service_udp.udp.sess_tx_datagrams: 2 - cluster.service_udp.update_attempt: 1 - cluster.service_udp.update_success: 1 - cluster.service_udp.upstream_cx_tx_bytes_total: 8 - udp.service.downstream_sess_active: 2 - udp.service.downstream_sess_rx_bytes: 8 - udp.service.downstream_sess_rx_datagrams: 2 - udp.service.downstream_sess_total: 2 - cluster.service_udp.upstream_cx_connect_ms: No recorded values - cluster.service_udp.upstream_cx_length_ms: No recorded values diff --git a/examples/udp/verify.sh b/examples/udp/verify.sh deleted file mode 100755 index 7ebdad6dd6c7..000000000000 --- a/examples/udp/verify.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -e - -export NAME=udp -export PORT_PROXY="${UDP_PORT_PROXY:-12100}" -export PORT_ADMIN="${UDP_PORT_ADMIN:-12101}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Send some UDP packets" -echo -n HELO | nc -4u -w1 127.0.0.1 "${PORT_PROXY}" -echo -n OLEH | nc -4u -w1 127.0.0.1 "${PORT_PROXY}" - -run_log "Check backend log" -"${DOCKER_COMPOSE[@]}" logs service-udp | grep HELO -"${DOCKER_COMPOSE[@]}" logs service-udp | grep OLEH - -run_log "Check admin stats" -curl -s "http://127.0.0.1:${PORT_ADMIN}/stats" | grep udp | grep -v "\: 0" diff --git a/examples/verify-common.sh b/examples/verify-common.sh deleted file mode 100644 index c6c0692b944c..000000000000 --- a/examples/verify-common.sh +++ /dev/null @@ -1,252 +0,0 @@ -#!/bin/bash -e - -DELAY="${DELAY:-0}" -DOCKER_NO_PULL="${DOCKER_NO_PULL:-}" -MANUAL="${MANUAL:-}" -NAME="${NAME:-}" -PATHS="${PATHS:-.}" -UPARGS="${UPARGS:-}" -ENVOY_EXAMPLES_DEBUG="${ENVOY_EXAMPLES_DEBUG:-}" - - -if [[ -n "$DOCKER_COMPOSE" ]]; then - read -ra DOCKER_COMPOSE <<< "$DOCKER_COMPOSE" -else - DOCKER_COMPOSE=(docker compose) -fi - -run_log () { - echo -e "\n> [${NAME}] ${*}" -} - -bring_up_example_stack () { - local args path up_args - args=("${UPARGS[@]}") - path="$1" - read -ra up_args <<< "up --quiet-pull --pull missing --build --wait -d ${args[*]}" - - if [[ -z "$DOCKER_NO_PULL" ]]; then - run_log "Pull the images ($path)" - "${DOCKER_COMPOSE[@]}" pull -q - echo - fi - run_log "Bring up services ($path)" - "${DOCKER_COMPOSE[@]}" "${up_args[@]}" || return 1 - - if [[ -n "$ENVOY_EXAMPLES_DEBUG" ]]; then - echo "----------------------------------------------" - docker system df -v - echo - sudo du -ch / | grep "[0-9]G" - echo - df -h - echo - echo "----------------------------------------------" - fi - echo -} - -bring_up_example () { - local path paths - read -ra paths <<< "$(echo "$PATHS" | tr ',' ' ')" - - for path in "${paths[@]}"; do - pushd "$path" > /dev/null || return 1 - bring_up_example_stack "$path" || { - echo "ERROR: starting ${NAME} ${path}" >&2 - return 1 - } - popd > /dev/null || return 1 - done - if [[ "$DELAY" -ne "0" ]]; then - run_log "Snooze for ${DELAY} while ${NAME} gets started" - sleep "$DELAY" - fi - for path in "${paths[@]}"; do - pushd "$path" > /dev/null || return 1 - "${DOCKER_COMPOSE[@]}" ps - "${DOCKER_COMPOSE[@]}" logs - popd > /dev/null || return 1 - done -} - -bring_down_example () { - local path paths - read -ra paths <<< "$(echo "$PATHS" | tr ',' ' ')" - for path in "${paths[@]}"; do - pushd "$path" > /dev/null || return 1 - cleanup_stack "$path" || { - echo "ERROR: cleanup ${NAME} ${path}" >&2 - } - popd > /dev/null - done -} - -cleanup_stack () { - local path down_args - path="$1" - down_args=(--remove-orphans) - - if [[ -n "$DOCKER_RMI_CLEANUP" ]]; then - down_args+=(--rmi all) - fi - - # Remove sandbox volumes by default - if [[ -z "$DOCKER_SAVE_VOLUMES" ]]; then - down_args+=(--volumes) - fi - - run_log "Cleanup ($path)" - "${DOCKER_COMPOSE[@]}" down "${down_args[@]}" -} - -debug_failure () { - >&2 echo "FAILURE DEBUG" - >&2 echo "DISK SPACE" - df -h - >&2 echo "DOCKER COMPOSE LOGS" - "${DOCKER_COMPOSE[@]}" logs - >&2 echo "DOCKER COMPOSE PS" - "${DOCKER_COMPOSE[@]}" ps -} - -cleanup () { - local code="$?" - - if [[ "$code" -ne 0 ]]; then - debug_failure - fi - - bring_down_example - - if type -t finally &> /dev/null; then - finally - fi - - if [[ "$code" -ne 0 ]]; then - run_log Failed - else - run_log Success - fi - echo -} - -_curl () { - local arg curl_command - curl_command=(curl -s) - if [[ ! "$*" =~ "-X" ]]; then - curl_command+=(-X GET) - fi - for arg in "${@}"; do - curl_command+=("$arg") - done - "${curl_command[@]}" || { - echo "ERROR: curl (${curl_command[*]})" >&2 - return 1 - } -} - -move_if_exists () { - if [ -e "$1" ]; then - mv "$1" "$2" - else - echo "Warning: $1 does not exist. Skipping move operation." - fi -} - -responds_with () { - local expected response - expected="$1" - shift - response=$(_curl "${@}") - grep -Fs "$expected" <<< "$response" || { - echo "ERROR: curl (${*})" >&2 - echo "EXPECTED:" >&2 - echo "$expected" >&2 - echo "RECEIVED:" >&2 - echo "$response" >&2 - return 1 - } -} - -responds_without () { - local expected response - expected="$1" - shift - response=$(_curl "${@}") - # shellcheck disable=2266 - grep -s "$expected" <<< "$response" | [[ "$(wc -l)" -eq 0 ]] || { - echo "ERROR: curl (${*})" >&2 - echo "DID NOT EXPECT: $expected" >&2 - echo "RECEIVED:" >&2 - echo "$response" >&2 - return 1 - } -} - -responds_with_header () { - local expected response - expected="$1" - shift - response=$(_curl --head "${@}") - grep -s "$expected" <<< "$response" || { - echo "ERROR: curl (${*})" >&2 - echo "EXPECTED HEADER:" >&2 - echo "$expected" >&2 - echo "RECEIVED:" >&2 - echo "$response" >&2 - return 1 - } -} - -responds_without_header () { - local expected response - expected="$1" - shift - response=$(_curl --head "${@}") - # shellcheck disable=2266 - grep -s "$expected" <<< "$response" | [[ "$(wc -l)" -eq 0 ]] || { - echo "ERROR: curl (${*})" >&2 - echo "DID NOT EXPECT HEADER: $expected" >&2 - echo "RECEIVED:" >&2 - echo "$response" >&2 - return 1 - } -} - -wait_for () { - local i=1 returns=1 seconds="$1" - shift - while ((i<=seconds)); do - if "${@}" &> /dev/null; then - returns=0 - break - else - sleep 1 - ((i++)) - fi - done - if [[ "$returns" != 0 ]]; then - echo "Wait (${seconds}) failed: ${*}" >&2 - fi - return "$returns" -} - -trap 'cleanup' EXIT - -if [[ -z "$NAME" ]]; then - echo "ERROR: You must set the '$NAME' variable before sourcing this script" >&2 - exit 1 -fi - -if [[ -z "$MANUAL" ]]; then - bring_up_example -fi - - -# These allow the functions to be used in subshells, e.g. in `wait_for` -export -f responds_with -export -f responds_without -export -f responds_with_header -export -f responds_without_header -export -f _curl diff --git a/examples/vrp-litmus/Dockerfile-vrp b/examples/vrp-litmus/Dockerfile-vrp deleted file mode 100644 index f0e6704d6d21..000000000000 --- a/examples/vrp-litmus/Dockerfile-vrp +++ /dev/null @@ -1 +0,0 @@ -FROM envoyproxy/envoy-google-vrp-dev:latest diff --git a/examples/vrp-litmus/README.md b/examples/vrp-litmus/README.md deleted file mode 100644 index 58c14b3fd8cb..000000000000 --- a/examples/vrp-litmus/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Simple litmus test to verify the VRP image in CI. For more details on VRP, -please see -https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/google_vrp. diff --git a/examples/vrp-litmus/docker-compose.yaml b/examples/vrp-litmus/docker-compose.yaml deleted file mode 100644 index e74efae098ee..000000000000 --- a/examples/vrp-litmus/docker-compose.yaml +++ /dev/null @@ -1,11 +0,0 @@ -services: - - vrp: - build: - context: . - dockerfile: Dockerfile-vrp - environment: - ENVOY_EDGE_EXTRA_ARGS: "" - ENVOY_ORIGIN_EXTRA_ARGS: "" - ports: - - "10000:10000" diff --git a/examples/vrp-litmus/verify.sh b/examples/vrp-litmus/verify.sh deleted file mode 100755 index 02791785c628..000000000000 --- a/examples/vrp-litmus/verify.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -e - -export NAME=vrp-litmus -export DELAY=10 - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -run_log "Test proxy" -responds_with \ - normal \ - https://localhost:10000/content \ - -k diff --git a/examples/vrp-local/Dockerfile-vrp b/examples/vrp-local/Dockerfile-vrp deleted file mode 100644 index 71f9b502e903..000000000000 --- a/examples/vrp-local/Dockerfile-vrp +++ /dev/null @@ -1 +0,0 @@ -FROM envoy-google-vrp:local diff --git a/examples/vrp-local/README.md b/examples/vrp-local/README.md deleted file mode 100644 index 55d3dca8a801..000000000000 --- a/examples/vrp-local/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Simple test to verify local Envoy binary injection into the VRP image. For more -details on VRP, please see -https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/google_vrp. diff --git a/examples/vrp-local/docker-compose.yaml b/examples/vrp-local/docker-compose.yaml deleted file mode 100644 index e74efae098ee..000000000000 --- a/examples/vrp-local/docker-compose.yaml +++ /dev/null @@ -1,11 +0,0 @@ -services: - - vrp: - build: - context: . - dockerfile: Dockerfile-vrp - environment: - ENVOY_EDGE_EXTRA_ARGS: "" - ENVOY_ORIGIN_EXTRA_ARGS: "" - ports: - - "10000:10000" diff --git a/examples/vrp-local/verify.sh b/examples/vrp-local/verify.sh deleted file mode 100755 index 201bb2837e7c..000000000000 --- a/examples/vrp-local/verify.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -e - -export NAME=vrp-local -export MANUAL=true - -# This sandbox is not really a sandbox (atm) and is only here for testing purposes. -# It is also not really structured in the same way and tends to be the hardest to fix -# when things change. - -# It tests 3 things -# - run with default (prebuilt) container -# - build container with custom Envoy (mocked) -# - rebuild and run container with default (mocked) binary - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - - -tag_default_vrp () { - # Image should already be present in CI - if [[ -z "$DOCKER_NO_PULL" ]]; then - docker pull -q envoyproxy/envoy:google-vrp-dev - fi - docker tag envoyproxy/envoy:google-vrp-dev envoy-google-vrp:local -} - -rebuild_vrp () { - pushd "$(dirname "${BASH_SOURCE[0]}")/../.." > /dev/null - # Follow instructions from - # https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/google_vrp#rebuilding-the-docker-image, - # but here we just use a mock Envoy and mock tools. - mkdir -p linux/arm64 linux/amd64 mockbin/utils - - echo "echo 'VRP PROXY MOCK 2'" > mockbin/envoy - chmod +x mockbin/envoy - touch mockbin/utils/su-exec - - tar czf release.tar.zst -C mockbin . - cp release.tar.zst linux/amd64 - mv release.tar.zst linux/arm64 - touch linux/amd64/schema_validator_tool - touch linux/arm64/schema_validator_tool - - ./ci/docker_rebuild_google-vrp.sh "$@" - popd > /dev/null -} - -test_vrp () { - wait_for 10 bash -c "responds_with 'normal' https://localhost:10000/content -k" - run_log "Test proxy" - responds_with \ - normal \ - https://localhost:10000/content \ - -k -} - -# Running this does not currently work with buildkit (even if that is how it is built). -export DOCKER_BUILDKIT=0 - -# Test running the default build -tag_default_vrp -bring_up_example -test_vrp -bring_down_example - -# Test a build with custom binary -echo "echo 'VRP PROXY MOCK'" > /tmp/envoy -chmod +x /tmp/envoy -rebuild_vrp /tmp/envoy -docker run --rm --entrypoint=/bin/sh envoy-google-vrp:local -c "/usr/local/bin/envoy | grep MOCK" - -# Test rebuilding and running the default build (with some mock tools) -rebuild_vrp -bring_up_example -docker run --rm --entrypoint=/bin/sh envoy-google-vrp:local -c "/usr/local/bin/envoy | grep 'MOCK 2'" diff --git a/examples/wasm-cc/BUILD b/examples/wasm-cc/BUILD deleted file mode 100644 index 2ea0b7d13906..000000000000 --- a/examples/wasm-cc/BUILD +++ /dev/null @@ -1,52 +0,0 @@ -load("@bazel_skylib//lib:selects.bzl", "selects") -load( - "//bazel:envoy_build_system.bzl", - "envoy_package", -) -load("//bazel/wasm:wasm.bzl", "envoy_wasm_cc_binary") - -licenses(["notice"]) # Apache 2 - -envoy_package() - -exports_files(["example.rst"]) - -selects.config_setting_group( - name = "include_wasm_config", - match_all = [ - "//bazel:x86", - "//bazel:wasm_v8", - ], -) - -filegroup( - name = "configs", - srcs = glob([ - "**/*.wasm", - ]) + select({ - ":include_wasm_config": glob( - [ - "**/*.yaml", - ], - exclude = [ - "**/*docker-compose*.yaml", - ], - ), - "//conditions:default": [], - }), -) - -envoy_wasm_cc_binary( - name = "envoy_filter_http_wasm_example.wasm", - srcs = ["envoy_filter_http_wasm_example.cc"], -) - -envoy_wasm_cc_binary( - name = "envoy_filter_http_wasm_updated_example.wasm", - srcs = ["envoy_filter_http_wasm_updated_example.cc"], -) - -filegroup( - name = "files", - srcs = glob(["**/*"], exclude = ["example.rst"]), -) diff --git a/examples/wasm-cc/Dockerfile-proxy b/examples/wasm-cc/Dockerfile-proxy deleted file mode 100644 index 8c578ff715dc..000000000000 --- a/examples/wasm-cc/Dockerfile-proxy +++ /dev/null @@ -1,5 +0,0 @@ -FROM envoyproxy/envoy:dev -COPY ./envoy.yaml /etc/envoy.yaml -COPY ./lib/envoy_filter_http_wasm_example.wasm /lib/envoy_filter_http_wasm_example.wasm -RUN chmod go+r /etc/envoy.yaml /lib/envoy_filter_http_wasm_example.wasm -CMD ["/usr/local/bin/envoy", "-c", "/etc/envoy.yaml", "--service-cluster", "proxy"] diff --git a/examples/wasm-cc/README.md b/examples/wasm-cc/README.md deleted file mode 100644 index f5e04fd7503a..000000000000 --- a/examples/wasm-cc/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/wasm-cc). diff --git a/examples/wasm-cc/docker-compose-wasm.yaml b/examples/wasm-cc/docker-compose-wasm.yaml deleted file mode 100644 index e9527a2f4b36..000000000000 --- a/examples/wasm-cc/docker-compose-wasm.yaml +++ /dev/null @@ -1,38 +0,0 @@ -services: - wasm_compile_update: - build: - context: ../shared/build - command: > - bash -c " - bazel build --experimental_repository_downloader_retries=2 --disk_cache=/tmp/disk_cache - --repository_cache=/tmp/repository_cache --experimental_repository_cache_hardlinks - //examples/wasm-cc:envoy_filter_http_wasm_updated_example.wasm - && cp -a bazel-bin/examples/wasm-cc/*updated*.wasm /output" - entrypoint: /source/examples/shared/build/build-entrypoint.sh - environment: - - BUILD_UID=${UID:-1000} - - TEST_TMPDIR=/tmp - working_dir: /source - volumes: - - ${ENVOY_DOCKER_BUILD_DIR:-/tmp/envoy-docker-build}:/tmp - - ../..:/source - - ./lib:/output - - wasm_compile: - build: - context: ../shared/build - command: > - bash -c " - bazel build --experimental_repository_downloader_retries=2 --disk_cache=/tmp/disk_cache - --repository_cache=/tmp/repository_cache --experimental_repository_cache_hardlinks - //examples/wasm-cc:envoy_filter_http_wasm_example.wasm - && cp -a bazel-bin/examples/wasm-cc/* /output" - entrypoint: /source/examples/shared/build/build-entrypoint.sh - environment: - - BUILD_UID=${UID:-1000} - - TEST_TMPDIR=/tmp - working_dir: /source - volumes: - - ${ENVOY_DOCKER_BUILD_DIR:-/tmp/envoy-docker-build}:/tmp - - ../..:/source - - ./lib:/output diff --git a/examples/wasm-cc/docker-compose.yaml b/examples/wasm-cc/docker-compose.yaml deleted file mode 100644 index f9edb0aec44d..000000000000 --- a/examples/wasm-cc/docker-compose.yaml +++ /dev/null @@ -1,17 +0,0 @@ -services: - - proxy: - build: - context: . - dockerfile: Dockerfile-proxy - depends_on: - - web_service - ports: - - "8000:8000" - - "8001:8001" - - web_service: - environment: - - PORT=9000 - build: - context: ../shared/echo diff --git a/examples/wasm-cc/envoy.yaml b/examples/wasm-cc/envoy.yaml deleted file mode 100644 index f580d2f88f55..000000000000 --- a/examples/wasm-cc/envoy.yaml +++ /dev/null @@ -1,128 +0,0 @@ -static_resources: - listeners: - - name: listener_0 - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: auto - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: web_service - - http_filters: - - name: envoy.filters.http.wasm - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - name: "my_plugin" - root_id: "my_root_id" - # if your wasm filter requires custom configuration you can add - # as follows - configuration: - "@type": "type.googleapis.com/google.protobuf.StringValue" - value: | - {} - vm_config: - vm_id: "my_vm_id" - code: - local: - filename: "lib/envoy_filter_http_wasm_example.wasm" - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - name: listener_1 - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: auto - stat_prefix: ingress_http2 - route_config: - name: local_route2 - virtual_hosts: - - name: local_service2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: web_service_with_wasm_filter - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: web_service - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: web_service - port_value: 9000 - - name: web_service_with_wasm_filter - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: web_service - port_value: 9000 - typed_extension_protocol_options: - envoy.extensions.upstreams.http.v3.HttpProtocolOptions: - "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions - upstream_http_protocol_options: - auto_sni: false - auto_san_validation: false - explicit_http_config: - http2_protocol_options: {} - http_filters: - - name: envoy.filters.http.wasm - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - name: "my_plugin" - root_id: "my_root_id" - # if your wasm filter requires custom configuration you can add - # as follows - configuration: - "@type": "type.googleapis.com/google.protobuf.StringValue" - value: | - {} - vm_config: - vm_id: "my_vm_id" - code: - local: - filename: "lib/envoy_filter_http_wasm_example.wasm" - - name: envoy.filters.http.upstream_codec - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.upstream_codec.v3.UpstreamCodec diff --git a/examples/wasm-cc/envoy_filter_http_wasm_example.cc b/examples/wasm-cc/envoy_filter_http_wasm_example.cc deleted file mode 100644 index 06478271add8..000000000000 --- a/examples/wasm-cc/envoy_filter_http_wasm_example.cc +++ /dev/null @@ -1,91 +0,0 @@ -// NOLINT(namespace-envoy) -#include -#include -#include - -#include "proxy_wasm_intrinsics.h" - -class ExampleRootContext : public RootContext { -public: - explicit ExampleRootContext(uint32_t id, std::string_view root_id) : RootContext(id, root_id) {} - - bool onStart(size_t) override; - bool onConfigure(size_t) override; - void onTick() override; -}; - -class ExampleContext : public Context { -public: - explicit ExampleContext(uint32_t id, RootContext* root) : Context(id, root) {} - - void onCreate() override; - FilterHeadersStatus onRequestHeaders(uint32_t headers, bool end_of_stream) override; - FilterDataStatus onRequestBody(size_t body_buffer_length, bool end_of_stream) override; - FilterHeadersStatus onResponseHeaders(uint32_t headers, bool end_of_stream) override; - FilterDataStatus onResponseBody(size_t body_buffer_length, bool end_of_stream) override; - void onDone() override; - void onLog() override; - void onDelete() override; -}; -static RegisterContextFactory register_ExampleContext(CONTEXT_FACTORY(ExampleContext), - ROOT_FACTORY(ExampleRootContext), - "my_root_id"); - -bool ExampleRootContext::onStart(size_t) { - LOG_TRACE("onStart"); - return true; -} - -bool ExampleRootContext::onConfigure(size_t) { - LOG_TRACE("onConfigure"); - proxy_set_tick_period_milliseconds(1000); // 1 sec - return true; -} - -void ExampleRootContext::onTick() { LOG_TRACE("onTick"); } - -void ExampleContext::onCreate() { LOG_WARN(std::string("onCreate " + std::to_string(id()))); } - -FilterHeadersStatus ExampleContext::onRequestHeaders(uint32_t, bool) { - LOG_DEBUG(std::string("onRequestHeaders ") + std::to_string(id())); - auto result = getRequestHeaderPairs(); - auto pairs = result->pairs(); - LOG_INFO(std::string("headers: ") + std::to_string(pairs.size())); - for (auto& p : pairs) { - LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second)); - } - return FilterHeadersStatus::Continue; -} - -FilterHeadersStatus ExampleContext::onResponseHeaders(uint32_t, bool) { - LOG_DEBUG(std::string("onResponseHeaders ") + std::to_string(id())); - auto result = getResponseHeaderPairs(); - auto pairs = result->pairs(); - LOG_INFO(std::string("headers: ") + std::to_string(pairs.size())); - for (auto& p : pairs) { - LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second)); - } - addResponseHeader("X-Wasm-custom", "FOO"); - replaceResponseHeader("content-type", "text/plain; charset=utf-8"); - removeResponseHeader("content-length"); - return FilterHeadersStatus::Continue; -} - -FilterDataStatus ExampleContext::onRequestBody(size_t body_buffer_length, - bool /* end_of_stream */) { - auto body = getBufferBytes(WasmBufferType::HttpRequestBody, 0, body_buffer_length); - LOG_ERROR(std::string("onRequestBody ") + std::string(body->view())); - return FilterDataStatus::Continue; -} - -FilterDataStatus ExampleContext::onResponseBody(size_t body_buffer_length, - bool /* end_of_stream */) { - setBuffer(WasmBufferType::HttpResponseBody, 0, body_buffer_length, "Hello, world\n"); - return FilterDataStatus::Continue; -} - -void ExampleContext::onDone() { LOG_WARN(std::string("onDone " + std::to_string(id()))); } - -void ExampleContext::onLog() { LOG_WARN(std::string("onLog " + std::to_string(id()))); } - -void ExampleContext::onDelete() { LOG_WARN(std::string("onDelete " + std::to_string(id()))); } diff --git a/examples/wasm-cc/envoy_filter_http_wasm_updated_example.cc b/examples/wasm-cc/envoy_filter_http_wasm_updated_example.cc deleted file mode 100644 index 67e6d24d96ab..000000000000 --- a/examples/wasm-cc/envoy_filter_http_wasm_updated_example.cc +++ /dev/null @@ -1,91 +0,0 @@ -// NOLINT(namespace-envoy) -#include -#include -#include - -#include "proxy_wasm_intrinsics.h" - -class ExampleRootContext : public RootContext { -public: - explicit ExampleRootContext(uint32_t id, std::string_view root_id) : RootContext(id, root_id) {} - - bool onStart(size_t) override; - bool onConfigure(size_t) override; - void onTick() override; -}; - -class ExampleContext : public Context { -public: - explicit ExampleContext(uint32_t id, RootContext* root) : Context(id, root) {} - - void onCreate() override; - FilterHeadersStatus onRequestHeaders(uint32_t headers, bool end_of_stream) override; - FilterDataStatus onRequestBody(size_t body_buffer_length, bool end_of_stream) override; - FilterHeadersStatus onResponseHeaders(uint32_t headers, bool end_of_stream) override; - FilterDataStatus onResponseBody(size_t body_buffer_length, bool end_of_stream) override; - void onDone() override; - void onLog() override; - void onDelete() override; -}; -static RegisterContextFactory register_ExampleContext(CONTEXT_FACTORY(ExampleContext), - ROOT_FACTORY(ExampleRootContext), - "my_root_id"); - -bool ExampleRootContext::onStart(size_t) { - LOG_TRACE("onStart"); - return true; -} - -bool ExampleRootContext::onConfigure(size_t) { - LOG_TRACE("onConfigure"); - proxy_set_tick_period_milliseconds(1000); // 1 sec - return true; -} - -void ExampleRootContext::onTick() { LOG_TRACE("onTick"); } - -void ExampleContext::onCreate() { LOG_WARN(std::string("onCreate " + std::to_string(id()))); } - -FilterHeadersStatus ExampleContext::onRequestHeaders(uint32_t, bool) { - LOG_DEBUG(std::string("onRequestHeaders ") + std::to_string(id())); - auto result = getRequestHeaderPairs(); - auto pairs = result->pairs(); - LOG_INFO(std::string("headers: ") + std::to_string(pairs.size())); - for (auto& p : pairs) { - LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second)); - } - return FilterHeadersStatus::Continue; -} - -FilterHeadersStatus ExampleContext::onResponseHeaders(uint32_t, bool) { - LOG_DEBUG(std::string("onResponseHeaders ") + std::to_string(id())); - auto result = getResponseHeaderPairs(); - auto pairs = result->pairs(); - LOG_INFO(std::string("headers: ") + std::to_string(pairs.size())); - for (auto& p : pairs) { - LOG_INFO(std::string(p.first) + std::string(" -> ") + std::string(p.second)); - } - addResponseHeader("X-Wasm-custom", "BAR"); - replaceResponseHeader("content-type", "text/html; charset=utf-8"); - removeResponseHeader("content-length"); - return FilterHeadersStatus::Continue; -} - -FilterDataStatus ExampleContext::onRequestBody(size_t body_buffer_length, - bool /* end_of_stream */) { - auto body = getBufferBytes(WasmBufferType::HttpRequestBody, 0, body_buffer_length); - LOG_ERROR(std::string("onRequestBody ") + std::string(body->view())); - return FilterDataStatus::Continue; -} - -FilterDataStatus ExampleContext::onResponseBody(size_t /* body_buffer_length */, - bool /* end_of_stream */) { - setBuffer(WasmBufferType::HttpResponseBody, 0, 17, "Hello, Wasm world"); - return FilterDataStatus::Continue; -} - -void ExampleContext::onDone() { LOG_WARN(std::string("onDone " + std::to_string(id()))); } - -void ExampleContext::onLog() { LOG_WARN(std::string("onLog " + std::to_string(id()))); } - -void ExampleContext::onDelete() { LOG_WARN(std::string("onDelete " + std::to_string(id()))); } diff --git a/examples/wasm-cc/example.rst b/examples/wasm-cc/example.rst deleted file mode 100644 index 18be02fa13e3..000000000000 --- a/examples/wasm-cc/example.rst +++ /dev/null @@ -1,184 +0,0 @@ -.. _install_sandboxes_wasm_filter: - -Wasm C++ filter -=============== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -.. sidebar:: Compatibility - - The provided Wasm binary was compiled for the ``x86_64`` architecture. If you would like to use this sandbox - with the ``arm64`` architecture, change directory to ``examples/wasm-cc`` and skip to Step 3. - -This sandbox demonstrates a basic :ref:`Envoy Wasm filter ` written in C++ which injects -content into the body of an ``HTTP`` response, and adds and updates some headers. - -It also takes you through the steps required to build your own C++ :ref:`Wasm filter `, -and run it with Envoy. - -Step 1: Start all of our containers -*********************************** - -First lets start the containers - an Envoy proxy which uses a Wasm Filter, and a backend which echos back our request. -The Envoy configuration exposes two listeners, the first one listens in port 8000 which contains the wasm filter in -the listener filter chain. The second one listens in port 8001 routing to a cluster containing the wasm filter in the -cluster filter chain. - -Change to the ``examples/wasm-cc`` folder in the Envoy repo, and start the composition: - -.. code-block:: console - - $ pwd - envoy/examples/wasm-cc - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------- - wasm_proxy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp - wasm_web_service_1 node ./index.js Up - -Step 2: Check web response -************************** - -The Wasm filter should inject "Hello, world" at the end of the response body when you make a request to the proxy. - -.. code-block:: console - - $ curl -s http://localhost:8000 | grep "Hello, world" - }Hello, world - -The filter also sets the ``content-type`` header to ``text/plain``, and adds a custom ``x-wasm-custom`` header. - -.. code-block:: console - - $ curl -v http://localhost:8000 | grep "content-type: " - content-type: text/plain; charset=utf-8 - - $ curl -v http://localhost:8000 | grep "x-wasm-custom: " - x-wasm-custom: FOO - -Similar outputs could be obtained in the second listener routing to the cluster with upstream wasm filter. - -.. code-block:: console - - $ curl -s http://localhost:8001 | grep "Hello, world" - }Hello, world - - $ curl -v http://localhost:8001 | grep "content-type: " - content-type: text/plain; charset=utf-8 - - $ curl -v http://localhost:8001 | grep "x-wasm-custom: " - x-wasm-custom: FOO - -Step 3: Compile the updated filter -********************************** - -There are two source code files provided for the Wasm filter. - -:download:`envoy_filter_http_wasm_example.cc <_include/wasm-cc/envoy_filter_http_wasm_example.cc>` provides the source code for -the included prebuilt binary. - -:download:`envoy_filter_http_wasm_updated_example.cc <_include/wasm-cc/envoy_filter_http_wasm_updated_example.cc>` makes a few -changes to the original. - -The following diff shows the changes that have been made: - -.. literalinclude:: _include/wasm-cc/envoy_filter_http_wasm_updated_example.cc - :diff: _include/wasm-cc/envoy_filter_http_wasm_example.cc - -.. warning:: - - These instructions for compiling an updated Wasm binary use the - `envoyproxy/envoy-build-ubuntu `_ image. - You will need 4-5GB of disk space to accommodate this image. - -Export ``UID`` from your host system. This will ensure that the binary created inside the build container has the same permissions -as your host user: - -.. code-block:: console - - $ export UID - -.. note:: - - The build composition is designed to work in a similar way to the ``./ci/run_envoy_docker.sh`` command in the Envoy repo. - - Bazel temporary artefacts are created in ``/tmp/envoy-docker-build`` with the uid taken from the ``UID`` env var. - -Stop the proxy server and compile the Wasm binary with the updated code: - -.. code-block:: console - - $ docker compose stop proxy - $ docker compose -f docker-compose-wasm.yaml up --remove-orphans wasm_compile_update - -The compiled binary should now be in the ``lib`` folder. - -.. code-block:: console - - $ ls -l lib - total 120 - -r-xr-xr-x 1 root root 59641 Oct 20 00:00 envoy_filter_http_wasm_example.wasm - -r-xr-xr-x 1 root root 59653 Oct 20 10:16 envoy_filter_http_wasm_updated_example.wasm - -Step 4: Edit the Dockerfile and restart the proxy -************************************************* - -Edit the ``Dockerfile-proxy`` recipe provided in the example to use the updated binary you created in step 3. - -Find the ``COPY`` line that adds the Wasm binary to the image: - -.. literalinclude:: _include/wasm-cc/Dockerfile-proxy - :language: dockerfile - :emphasize-lines: 3 - :linenos: - -Replace this line with the following: - -.. code-block:: dockerfile - - COPY ./lib/envoy_filter_http_wasm_updated_example.wasm /lib/envoy_filter_http_wasm_example.wasm - -Now, rebuild and start the proxy container. - -.. code-block:: console - - $ docker compose up --build -d proxy - -Step 5: Check the proxy has been updated -**************************************** - -The Wasm filter should instead inject "Hello, Wasm world" at the end of the response body. - -.. code-block:: console - - $ curl -s http://localhost:8000 | grep "Hello, Wasm world" - }Hello, Wasm world - -The ``content-type`` and ``x-wasm-custom`` headers should also have changed - -.. code-block:: console - - $ curl -v http://localhost:8000 | grep "content-type: " - content-type: text/html; charset=utf-8 - - $ curl -v http://localhost:8000 | grep "x-wasm-custom: " - x-wasm-custom: BAR - -.. seealso:: - - :ref:`Envoy Wasm filter ` - Further information about the Envoy Wasm filter. - - :ref:`Envoy Wasm API(V3) ` - The Envoy Wasm API - version 3. - - `Proxy Wasm C++ SDK `_ - WebAssembly for proxies (C++ SDK) diff --git a/examples/wasm-cc/lib/envoy_filter_http_wasm_example.wasm b/examples/wasm-cc/lib/envoy_filter_http_wasm_example.wasm deleted file mode 100755 index df2554e971e8..000000000000 Binary files a/examples/wasm-cc/lib/envoy_filter_http_wasm_example.wasm and /dev/null differ diff --git a/examples/wasm-cc/verify.sh b/examples/wasm-cc/verify.sh deleted file mode 100755 index 179982db5ed5..000000000000 --- a/examples/wasm-cc/verify.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -e - -export NAME=wasm-cc -export UID - - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test connection" -responds_with \ - "Hello, world" \ - http://localhost:8000 - -run_log "Test content-type header" -responds_with_header \ - "content-type: text/plain" \ - http://localhost:8000 - -run_log "Test custom Wasm header" -responds_with_header \ - "x-wasm-custom: FOO" \ - http://localhost:8000 - -run_log "Bring down the proxy" -"${DOCKER_COMPOSE[@]}" stop proxy - -run_log "Compile updated Wasm filter" -"${DOCKER_COMPOSE[@]}" -f docker-compose-wasm.yaml up --quiet-pull --remove-orphans wasm_compile_update - -run_log "Check for the compiled update" -ls -l lib/*updated*wasm - -run_log "Edit the Docker recipe to use the updated binary" -sed -i'.bak' s/\\.\\/lib\\/envoy_filter_http_wasm_example.wasm/.\\/lib\\/envoy_filter_http_wasm_updated_example.wasm/ Dockerfile-proxy - -run_log "Bring the proxy back up" -"${DOCKER_COMPOSE[@]}" up --build -d proxy -wait_for 10 bash -c "\ - responds_with \ - 'Hello, Wasm world' \ - http://localhost:8000" - -run_log "Test updated connection" -responds_with \ - "Hello, Wasm world" \ - http://localhost:8000 - -run_log "Test updated content-type header" -responds_with_header \ - "content-type: text/html" \ - http://localhost:8000 - -run_log "Test updated Wasm header" -responds_with_header \ - "x-wasm-custom: BAR" \ - http://localhost:8000 - -# Restore original Dockerfile -mv Dockerfile-proxy.bak Dockerfile-proxy diff --git a/examples/websocket/README.md b/examples/websocket/README.md deleted file mode 100644 index 8473888649c3..000000000000 --- a/examples/websocket/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/websocket.html). diff --git a/examples/websocket/docker-compose.yaml b/examples/websocket/docker-compose.yaml deleted file mode 100644 index 198b486c03ff..000000000000 --- a/examples/websocket/docker-compose.yaml +++ /dev/null @@ -1,63 +0,0 @@ -services: - - client-ws: - build: - context: . - dockerfile: ../shared/websocket/Dockerfile - target: websocket-client - network_mode: host - restart: "no" - deploy: - replicas: 0 - - proxy-ws: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-ws.yaml - ports: - - "${PORT_PROXY0:-10000}:10000" - - proxy-ws-route: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-ws-route.yaml - ports: - - "${PORT_PROXY1:-15000}:10000" - - proxy-wss-wss: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-wss.yaml - ports: - - "${PORT_PROXY2:-20000}:10000" - - proxy-wss-passthrough: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: ./envoy-wss-passthrough.yaml - ports: - - "${PORT_PROXY3:-30000}:10000" - - service-ws: - build: - context: . - dockerfile: ../shared/websocket/Dockerfile - hostname: service-ws - command: -E ws-listen:0.0.0.0:80 literalreply:'[ws] HELO' - - service-wss: - build: - context: . - dockerfile: ../shared/websocket/Dockerfile - hostname: service-wss - command: wss-listen:0.0.0.0:443 literalreply:"[wss] HELO" --pkcs12-der /certs/output.pkcs12 - volumes: - - ./certs/output.pkcs12:/certs/output.pkcs12 diff --git a/examples/websocket/envoy-ws-route.yaml b/examples/websocket/envoy-ws-route.yaml deleted file mode 100644 index 04af21da098a..000000000000 --- a/examples/websocket/envoy-ws-route.yaml +++ /dev/null @@ -1,49 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_ws_to_ws - route_config: - name: local_route - virtual_hosts: - - name: app-ws - domains: - - "*" - routes: - - match: - prefix: "/ws" - route: - cluster: service_ws - upgrade_configs: - - upgrade_type: websocket - - match: - prefix: "/" - direct_response: - status: 200 - body: - inline_string: "NotWebSocket\n" - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service_ws - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_ws - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-ws - port_value: 80 diff --git a/examples/websocket/envoy-ws.yaml b/examples/websocket/envoy-ws.yaml deleted file mode 100644 index 7538081847b3..000000000000 --- a/examples/websocket/envoy-ws.yaml +++ /dev/null @@ -1,43 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_ws_to_ws - upgrade_configs: - - upgrade_type: websocket - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_ws - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - clusters: - - name: service_ws - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_ws - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-ws - port_value: 80 diff --git a/examples/websocket/envoy-wss-passthrough.yaml b/examples/websocket/envoy-wss-passthrough.yaml deleted file mode 100644 index 6634d483def6..000000000000 --- a/examples/websocket/envoy-wss-passthrough.yaml +++ /dev/null @@ -1,27 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.tcp_proxy - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy - cluster: service_wss_passthrough - stat_prefix: wss_passthrough - - clusters: - - name: service_wss_passthrough - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_wss_passthrough - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-wss - port_value: 443 diff --git a/examples/websocket/envoy-wss.yaml b/examples/websocket/envoy-wss.yaml deleted file mode 100644 index 039025ed0986..000000000000 --- a/examples/websocket/envoy-wss.yaml +++ /dev/null @@ -1,111 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_wss_to_wss - upgrade_configs: - - upgrade_type: websocket - route_config: - name: local_route - virtual_hosts: - - name: app - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_wss - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: service_wss - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_wss - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-wss - port_value: 443 - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext diff --git a/examples/websocket/example.rst b/examples/websocket/example.rst deleted file mode 100644 index c0226584f55c..000000000000 --- a/examples/websocket/example.rst +++ /dev/null @@ -1,196 +0,0 @@ -.. _install_sandboxes_websocket: - -WebSockets -========== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`openssl ` - Generate ``SSL`` keys and certificates. - -This example walks through some of the ways that Envoy can be configured to proxy WebSockets. - -It demonstrates terminating a WebSocket connection with and without ``TLS``, and provides some basic examples -of proxying to encrypted and non-encrypted upstream sockets. - -.. warning:: - - For the sake of simplicity, the examples provided here do not authenticate any client certificates, - or validate any of the provided certificates. - - When using ``TLS``, you are strongly encouraged to :ref:`validate ` - all certificates wherever possible. - - You should also :ref:`authenticate clients ` - where you control both sides of the connection, or relevant protocols are available. - -Step 1: Create a certificate file for wss -***************************************** - -Change directory to ``examples/websocket`` in the Envoy repository. - -.. code-block:: console - - $ pwd - envoy/examples/websocket - $ mkdir -p certs - $ openssl req -batch -new -x509 -nodes -keyout certs/key.pem -out certs/cert.pem - Generating a RSA private key - ..................................................................................................................+++++ - ......+++++ - writing new private key to 'certs/key.pem' - ----- - $ openssl pkcs12 -export -passout pass: -out certs/output.pkcs12 -inkey certs/key.pem -in certs/cert.pem - -Step 2: Build and start the sandbox -*********************************** - -This starts four proxies listening on ``localhost`` ports ``10000``, ``15000``, ``20000``, ``30000``. - -It also starts two upstream services, one ``ws`` and one ``wss``. - -The upstream services listen on the internal Docker network on ports ``80`` and ``443`` respectively. - -The socket servers are very trivial implementations, that simply output ``[ws] HELO`` and -``[wss] HELO`` in response to any input. - -.. code-block:: console - - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - --------------------------------------------------------------------------------------------------- - websocket_proxy-ws_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - websocket_proxy-ws-route_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:15000->10000/tcp - websocket_proxy-wss_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:20000->10000/tcp - websocket_proxy-wss-passthrough_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:30000->10000/tcp - websocket_service-ws_1 websocat -E ws-listen:0.0. ... Up - websocket_service-wss_1 websocat wss-listen:0.0.0. ... Up - -Step 3: Test proxying ``ws`` -> ``ws`` -************************************** - -The proxy listening on port ``10000`` terminates the WebSocket connection without ``TLS`` and then proxies -to an upstream socket, also without ``TLS``. - -In order for Envoy to terminate the WebSocket connection, the -:ref:`upgrade_configs ` -in :ref:`HttpConnectionManager ` -must be set, as can be seen in the provided :download:`ws -> ws configuration <_include/websocket/envoy-ws.yaml>`: - -.. literalinclude:: _include/websocket/envoy-ws.yaml - :language: yaml - :lines: 1-29 - :linenos: - :emphasize-lines: 13-14 - -You can start an interactive session with the socket as follows: - -.. code-block:: console - - $ docker run -ti --network=host solsson/websocat ws://localhost:10000 - HELO - [ws] HELO - GOODBYE - [ws] HELO - -Type ``Ctrl-c`` to exit the socket session. - -Step 4: Test proxying ``ws`` -> ``ws`` on specific route -******************************************************** - -The proxy listening on port ``15000`` terminates the WebSocket connection without ``TLS`` on specific route ``/ws`` and then proxies -to an upstream socket, also without ``TLS``. - -In order for Envoy to terminate the WebSocket connection, the -:ref:`upgrade_configs ` -in :ref:`RouteAction ` -must be set, as can be seen in the provided :download:`ws -> ws configuration <_include/websocket/envoy-ws-route.yaml>`: - -.. literalinclude:: _include/websocket/envoy-ws-route.yaml - :language: yaml - :lines: 19-25 - :linenos: - :emphasize-lines: 6-7 - :caption: :download:`envoy-ws-route.yaml <_include/websocket/envoy-ws-route.yaml>` - -You can start an interactive session with the socket as follows: - -.. code-block:: console - - $ docker run -ti --network=host solsson/websocat ws://localhost:15000/ws - HELO - [ws] HELO - GOODBYE - [ws] HELO - - $ curl http://localhost:15000 - NotWebSocket - - $ curl http://localhost:15000/ws - Only WebSocket connections are welcome here - -Type ``Ctrl-c`` to exit the socket session. - -Step 5: Test proxying ``wss`` -> ``wss`` -**************************************** - -The proxy listening on port ``20000`` terminates the WebSocket connection with ``TLS`` and then proxies -to an upstream ``TLS`` WebSocket. - -In addition to the -:ref:`upgrade_configs ` -in :ref:`HttpConnectionManager `, -the :download:`wss -> wss configuration <_include/websocket/envoy-wss.yaml>` adds a ``TLS`` -:ref:`transport_socket ` to both the -:ref:`listener ` and the -:ref:`cluster `. - -You can start an interactive session with the socket as follows: - -.. code-block:: console - - $ docker run -ti --network=host solsson/websocat --insecure wss://localhost:20000 - HELO - [wss] HELO - GOODBYE - [wss] HELO - -Type ``Ctrl-c`` to exit the socket session. - -Step 6: Test proxying ``wss`` passthrough -***************************************** - -The proxy listening on port ``30000`` passes through all ``TCP`` traffic to an upstream ``TLS`` WebSocket. - -The :download:`wss passthrough configuration <_include/websocket/envoy-wss-passthrough.yaml>` requires no ``TLS`` -or ``HTTP`` setup, and instead uses a simple -:ref:`tcp_proxy `. - -You can start an interactive session with the socket as follows: - -.. code-block:: console - - $ docker run -ti --network=host solsson/websocat --insecure wss://localhost:30000 - HELO - [wss] HELO - GOODBYE - [wss] HELO - -Type ``Ctrl-c`` to exit the socket session. - -.. seealso:: - - :ref:`Securing Envoy quick start guide ` - Outline of key concepts for securing Envoy. - - :ref:`Double proxy sandbox ` - An example of securing traffic between proxies with validation and - mutual authentication using ``mTLS`` with non-``HTTP`` traffic. - - :ref:`TLS sandbox ` - Examples of various ``TLS`` termination patterns with Envoy. diff --git a/examples/websocket/interact.sh b/examples/websocket/interact.sh deleted file mode 100644 index 6f507d5427b7..000000000000 --- a/examples/websocket/interact.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -e - -interact_ws () { - local port="$1" \ - protocol="$2" \ - backend="$3" \ - insecure="" - if [ "$protocol" == "wss" ]; then - insecure="--insecure" - fi - expect < ws" -"${DOCKER_COMPOSE[@]}" run client-ws "${PORT_PROXY0}" ws ws - -run_log "Interact with web socket ws -> ws for specific route" -"${DOCKER_COMPOSE[@]}" run client-ws "${PORT_PROXY1}/ws" ws ws - -run_log "Interact with web socket wss -> wss" -"${DOCKER_COMPOSE[@]}" run client-ws "${PORT_PROXY2}" wss wss - -run_log "Interact with web socket wss passthrough" -"${DOCKER_COMPOSE[@]}" run client-ws "${PORT_PROXY3}" wss wss diff --git a/examples/win32-front-proxy/Dockerfile-frontenvoy b/examples/win32-front-proxy/Dockerfile-frontenvoy deleted file mode 100644 index 3a3494f54c0d..000000000000 --- a/examples/win32-front-proxy/Dockerfile-frontenvoy +++ /dev/null @@ -1,6 +0,0 @@ -FROM envoyproxy/envoy-windows-dev:latest - -COPY ./front-envoy.yaml './front-envoy.yaml' -COPY ./start_envoy.ps1 ./start_envoy.ps1 -ENTRYPOINT ["powershell.exe", "./start_envoy.ps1"] - diff --git a/examples/win32-front-proxy/Dockerfile-service b/examples/win32-front-proxy/Dockerfile-service deleted file mode 100644 index 925bf95e6c96..000000000000 --- a/examples/win32-front-proxy/Dockerfile-service +++ /dev/null @@ -1,12 +0,0 @@ -FROM envoyproxy/envoy-windows-dev:latest - -COPY ./setup_python.ps1 / - -RUN powershell.exe .\\setup_python.ps1 -RUN pip3 install -q Flask==2.0.3 requests==2.18.4 - -RUN powershell mkdir code -ADD ./service.py ./code -ADD ./service-envoy.yaml ./service-envoy.yaml -ADD ./start_service.ps1 ./start_service.ps1 -ENTRYPOINT ["powershell.exe", "./start_service.ps1"] diff --git a/examples/win32-front-proxy/README.md b/examples/win32-front-proxy/README.md deleted file mode 100644 index cca1fdaf55f9..000000000000 --- a/examples/win32-front-proxy/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/win32_front_proxy.html) diff --git a/examples/win32-front-proxy/docker-compose.yaml b/examples/win32-front-proxy/docker-compose.yaml deleted file mode 100644 index edac3f7a95ad..000000000000 --- a/examples/win32-front-proxy/docker-compose.yaml +++ /dev/null @@ -1,24 +0,0 @@ -services: - - front-envoy: - build: - context: . - dockerfile: Dockerfile-frontenvoy - ports: - - "8080:8080" - - "8443:8443" - - "8003:8003" - - service1: - build: - context: . - dockerfile: Dockerfile-service - environment: - - SERVICE_NAME=1 - - service2: - build: - context: . - dockerfile: Dockerfile-service - environment: - - SERVICE_NAME=2 diff --git a/examples/win32-front-proxy/front-envoy.yaml b/examples/win32-front-proxy/front-envoy.yaml deleted file mode 100644 index de22d10fd204..000000000000 --- a/examples/win32-front-proxy/front-envoy.yaml +++ /dev/null @@ -1,170 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8080 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1 - - match: - prefix: "/service/2" - route: - cluster: service2 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - - address: - socket_address: - address: 0.0.0.0 - port_value: 8443 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/service/1" - route: - cluster: service1 - - match: - prefix: "/service/2" - route: - cluster: service2 - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem \ - # -days 3650 -nodes -subj '/CN=front-envoy' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: service1 - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service1 - port_value: 8000 - - name: service2 - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service2 - port_value: 8000 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 -layered_runtime: - layers: - - name: static_layer_0 - static_layer: - envoy: - resource_limits: - listener: - example_listener_name: - connection_limit: 10000 diff --git a/examples/win32-front-proxy/service-envoy.yaml b/examples/win32-front-proxy/service-envoy.yaml deleted file mode 100644 index f944baa6ff87..000000000000 --- a/examples/win32-front-proxy/service-envoy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 8000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - codec_type: AUTO - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: service - domains: - - "*" - routes: - - match: - prefix: "/service" - route: - cluster: local_service - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - clusters: - - name: local_service - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: local_service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 8081 diff --git a/examples/win32-front-proxy/service.py b/examples/win32-front-proxy/service.py deleted file mode 100644 index d08b0a897c9e..000000000000 --- a/examples/win32-front-proxy/service.py +++ /dev/null @@ -1,31 +0,0 @@ -from flask import Flask -import os -import requests -import socket -import sys - -app = Flask(__name__) - - -@app.route('/service/') -def hello(service_number): - return ( - 'Hello from behind Envoy (service {})! hostname: {} resolved' - 'hostname: {}\n'.format( - os.environ['SERVICE_NAME'], socket.gethostname(), - socket.gethostbyname(socket.gethostname()))) - - -@app.route('/trace/') -def trace(service_number): - if int(os.environ['SERVICE_NAME']) == 1: - requests.get("http://localhost:9000/trace/2") - return ( - 'Hello from behind Envoy (service {})! hostname: {} resolved' - 'hostname: {}\n'.format( - os.environ['SERVICE_NAME'], socket.gethostname(), - socket.gethostbyname(socket.gethostname()))) - - -if __name__ == "__main__": - app.run(host='127.0.0.1', port=8080, debug=True) diff --git a/examples/win32-front-proxy/setup_python.ps1 b/examples/win32-front-proxy/setup_python.ps1 deleted file mode 100644 index 0905a4b03062..000000000000 --- a/examples/win32-front-proxy/setup_python.ps1 +++ /dev/null @@ -1,54 +0,0 @@ -$ErrorActionPreference = "Stop"; - -function DownloadAndCheck -{ - param([string]$to, [string]$url, [string]$sha256) - - Write-Host "Downloading $url to $to..." - (New-Object System.Net.WebClient).DownloadFile($url, $to) - $actual = (Get-FileHash -Path $to -Algorithm SHA256).Hash - if ($actual -ne $sha256) { - Write-Host "Download of $url to $to is invalid, expected sha256: $sha256, but got: $actual"; - exit 1 - } - Write-Host "done." -} - -function AddToPath -{ - param([string] $directory) - - $oldPath = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path - $newPath = "$oldPath;$directory" - Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath - # Add to local path so subsequent commands have access to the executables they need - $env:PATH += ";$directory" - Write-Host "Added $directory to PATH" -} - -function RunAndCheckError -{ - param([string] $exe, [string[]] $argList, [Parameter(Mandatory=$false)] $isInstaller = $false) - - Write-Host "Running '$exe $argList'..." - if ($isInstaller) { - Write-Host "(running as Windows software installer)" - Start-Process $exe -ArgumentList "$argList" -Wait -NoNewWindow - } else { - &$exe $argList - if ($LASTEXITCODE -ne 0) { - Write-Host "$exe $argList exited with code $LASTEXITCODE" - exit $LASTEXITCODE - } - } - Write-Host "done." -} - -# Python3 (do not install via msys2 or the MS store's flavors, this version follows Win32 semantics) -DownloadAndCheck $env:TEMP\python3-installer.exe ` - https://www.python.org/ftp/python/3.8.5/python-3.8.5-amd64.exe ` - cd427c7b17337d7c13761ca20877d2d8be661bd30415ddc17072a31a65a91b64 -# python installer needs to be run as an installer with Start-Process -RunAndCheckError "$env:TEMP\python3-installer.exe" @("/quiet", "InstallAllUsers=1", "Include_launcher=0", "InstallLauncherAllUsers=0") $true -AddToPath $env:ProgramFiles\Python38 -AddToPath $env:ProgramFiles\Python38\Scripts diff --git a/examples/win32-front-proxy/start_envoy.ps1 b/examples/win32-front-proxy/start_envoy.ps1 deleted file mode 100644 index efe1e2592e24..000000000000 --- a/examples/win32-front-proxy/start_envoy.ps1 +++ /dev/null @@ -1 +0,0 @@ -& 'C:\\Program Files\\envoy\\envoy.exe' --config-path .\front-envoy.yaml --service-cluster front-proxy diff --git a/examples/win32-front-proxy/start_service.ps1 b/examples/win32-front-proxy/start_service.ps1 deleted file mode 100644 index 0aabb3b0b3de..000000000000 --- a/examples/win32-front-proxy/start_service.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -Start-Process -FilePath "python" -ArgumentList @("./code/service.py") - -$serviceName = "service$env:ServiceId" -& 'C:\\Program Files\\envoy\\envoy.exe' --config-path .\service-envoy.yaml --service-cluster $serviceName diff --git a/examples/zipkin/Dockerfile-zipkin b/examples/zipkin/Dockerfile-zipkin deleted file mode 100644 index f78c42d87ec3..000000000000 --- a/examples/zipkin/Dockerfile-zipkin +++ /dev/null @@ -1 +0,0 @@ -FROM openzipkin/zipkin:latest@sha256:da8177371c4a7aed7fd673196593c2ff104ce908f300e1971493587622f7a297 diff --git a/examples/zipkin/README.md b/examples/zipkin/README.md deleted file mode 100644 index 173c2fbd8b0d..000000000000 --- a/examples/zipkin/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/zipkin) diff --git a/examples/zipkin/_static/zipkin-ui-dependency.png b/examples/zipkin/_static/zipkin-ui-dependency.png deleted file mode 100644 index 3f0c68200820..000000000000 Binary files a/examples/zipkin/_static/zipkin-ui-dependency.png and /dev/null differ diff --git a/examples/zipkin/_static/zipkin-ui.png b/examples/zipkin/_static/zipkin-ui.png deleted file mode 100644 index 67dcb53b064d..000000000000 Binary files a/examples/zipkin/_static/zipkin-ui.png and /dev/null differ diff --git a/examples/zipkin/docker-compose.yaml b/examples/zipkin/docker-compose.yaml deleted file mode 100644 index 79c353c0adff..000000000000 --- a/examples/zipkin/docker-compose.yaml +++ /dev/null @@ -1,64 +0,0 @@ -services: - - envoy-front-proxy: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-front-proxy.yaml - depends_on: - zipkin: - condition: service_healthy - envoy-1: - condition: service_started - envoy-2: - condition: service_started - ports: - - "${PORT_PROXY:-10000}:10000" - - envoy-1: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-1.yaml - depends_on: - zipkin: - condition: service_healthy - service-1: - condition: service_healthy - envoy-2: - condition: service_started - - envoy-2: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - args: - ENVOY_CONFIG: envoy-2.yaml - depends_on: - zipkin: - condition: service_healthy - service-2: - condition: service_healthy - - service-1: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=1 - - service-2: - build: - context: ../shared/python - target: aiohttp-tracing-service - environment: - - SERVICE_NAME=2 - - zipkin: - build: - context: . - dockerfile: Dockerfile-zipkin - ports: - - "${PORT_UI:-9411}:9411" diff --git a/examples/zipkin/envoy-1.yaml b/examples/zipkin/envoy-1.yaml deleted file mode 100644 index b6e04501a5a9..000000000000 --- a/examples/zipkin/envoy-1.yaml +++ /dev/null @@ -1,123 +0,0 @@ -# This proxy listens on 2 ports: -# -# 10000 -> routes to `service-1` -# 10001 -> routes to `envoy-2` - -node: - # The cluster name is used by Zipkin to identify the proxy. - cluster: envoy-proxy-1 - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: zipkin - collector_endpoint: "/api/v2/spans" - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: service1_route - virtual_hosts: - - name: service1 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster1 - decorator: - operation: routeToService1 - - address: - socket_address: - address: 0.0.0.0 - port_value: 10001 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: zipkin - collector_endpoint: "/api/v2/spans" - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: egress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: envoy2_route - virtual_hosts: - - name: envoy2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2 - - clusters: - - name: service_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-1 - port_value: 8080 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-2 - port_value: 10000 - - name: zipkin - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: zipkin - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: zipkin - port_value: 9411 diff --git a/examples/zipkin/envoy-2.yaml b/examples/zipkin/envoy-2.yaml deleted file mode 100644 index ac502803ec27..000000000000 --- a/examples/zipkin/envoy-2.yaml +++ /dev/null @@ -1,71 +0,0 @@ -# This proxy listens on port 10000 and routes all queries to `service-2`. - -node: - # The cluster name is used by Zipkin to identify the proxy. - cluster: envoy-proxy-2 - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: INBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: zipkin - collector_endpoint: "/api/v2/spans" - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: service2_route - virtual_hosts: - - name: service2 - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service_cluster2 - decorator: - operation: routeToService2 - - clusters: - - name: service_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service-2 - port_value: 8080 - - name: zipkin - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: zipkin - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: zipkin - port_value: 9411 diff --git a/examples/zipkin/envoy-front-proxy.yaml b/examples/zipkin/envoy-front-proxy.yaml deleted file mode 100644 index 6f7a9520444b..000000000000 --- a/examples/zipkin/envoy-front-proxy.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# This proxy listens on port 10000, and routes the following paths: -# -# /trace/1 -> routes to `envoy-1` on port 10000 -# /trace/2 -> routes to `envoy-1` on port 10001 (for onward routing to `envoy-2`) - -node: - # The cluster name is used by Zipkin to identify the proxy. - cluster: envoy-proxy-front - -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - traffic_direction: OUTBOUND - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - generate_request_id: true - tracing: - provider: - name: envoy.tracers.zipkin - typed_config: - "@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig - collector_cluster: zipkin - collector_endpoint: "/api/v2/spans" - collector_endpoint_version: HTTP_JSON - codec_type: AUTO - stat_prefix: ingress_http - http_filters: - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - route_config: - name: proxy_routes - virtual_hosts: - - name: proxy - domains: - - "*" - routes: - - match: - prefix: "/trace/1" - route: - cluster: envoy_cluster1 - decorator: - operation: routeToEnvoy1 - - match: - prefix: "/trace/2" - route: - cluster: envoy_cluster2 - decorator: - operation: routeToEnvoy2ViaEnvoy1 - response_headers_to_add: - - header: - key: "x-b3-traceid" - value: "%REQ(x-b3-traceid)%" - - header: - key: "x-request-id" - value: "%REQ(x-request-id)%" - - clusters: - - name: envoy_cluster1 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster1 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10000 - - name: envoy_cluster2 - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: envoy_cluster2 - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: envoy-1 - port_value: 10001 - - name: zipkin - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: zipkin - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: zipkin - port_value: 9411 diff --git a/examples/zipkin/example.rst b/examples/zipkin/example.rst deleted file mode 100644 index 34c0f9c82e9e..000000000000 --- a/examples/zipkin/example.rst +++ /dev/null @@ -1,127 +0,0 @@ -.. _install_sandboxes_zipkin: - -Zipkin tracing -============== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -The Zipkin tracing sandbox demonstrates Envoy's :ref:`request tracing ` -capabilities using `Zipkin `_ as the tracing provider. - -In this example, 2 backend services are provided: - -- ``service-1`` -- ``service-2`` - -3 Envoy proxies are also provided to route requests to them: - -- ``envoy-front-proxy`` (:download:`envoy-front-proxy.yaml <_include/zipkin/envoy-front-proxy.yaml>`) -- ``envoy-1`` (:download:`envoy-1.yaml <_include/zipkin/envoy-1.yaml>`) -- ``envoy-2`` (:download:`envoy-2.yaml <_include/zipkin/envoy-2.yaml>`) - -Of these services, only the Envoy ``front-proxy`` service is exposed outside of the -:download:`composition <_include/zipkin/docker-compose.yaml>`, on port ``10000``. - -For ``service-1``, requests are routed based on the request path ``trace/1``, as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> ``service-1`` - -For ``service-2``, requests are routed based on the request path ``trace/2`` as follows: - - User -> Envoy(``envoy-front-proxy``) -> Envoy(``envoy-1``) -> Envoy(``envoy-2``) -> ``service-2`` - -All Envoy proxies are configured to collect request traces, as can be seen in their configurations, -propagating the spans (parent/child/shared context) generated by the Zipkin tracer to a Zipkin cluster. - -Each span records the latency of upstream API calls as well as information -needed to correlate the span with other related spans (e.g., the trace ID). - -The Zipkin collector provides a web UI for viewing the collected traces on port ``9411``. - -Step 1: Build the sandbox -************************* - -Change directory to ``examples/zipkin`` in the Envoy repository. - -To build this sandbox example, and start the example services run the following commands: - -.. code-block:: console - - $ pwd - envoy/examples/zipkin - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - - Name Command State Ports - ----------------------------------------------------------------------------------------------------------- - zipkin_envoy-1_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - zipkin_envoy-2_1 /docker-entrypoint.sh /usr ... Up 10000/tcp - zipkin_envoy-front-proxy_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp - zipkin_service-1_1 python3 /code/service.py Up (healthy) - zipkin_service-2_1 python3 /code/service.py Up (healthy) - zipkin_zipkin_1 start-zipkin Up (healthy) 9410/tcp, 0.0.0.0:9411->9411/tcp - -Step 2: Make a request to ``service-1`` -*************************************** - -Now send a request to ``service-1``, by calling http://localhost:10000/trace/1. - -This will be routed via 2 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` - -.. code-block:: console - - $ curl localhost:10000/trace/1 - Hello from behind Envoy (service 1)! - -Step 3: Make a request to ``service-2`` -*************************************** - -Now send a request to ``service-2``, by calling http://localhost:10000/trace/2. - -This will be routed via all 3 of the Envoy proxies: - -- ``front-proxy`` -- ``envoy-1`` -- ``envoy-2`` - -.. code-block:: console - - $ curl localhost:10000/trace/2 - Hello from behind Envoy (service 2)! - -Step 4: View the traces in Zipkin UI -************************************ - -Point your browser to http://localhost:9411 . - -You should see the Zipkin dashboard. - -Click the ``RUN QUERY`` button, and expand the traces by clicking ``EXPAND ALL``. - -Here you can explore the paths taken by the requests, as well as the latency incurred at each hop, -and other contextual information. - -Note that Zipkin identifies the Envoy proxies by the name provided in the bootstrap ``node/cluster`` configuration. - -.. image:: /start/sandboxes/_include/zipkin/_static/zipkin-ui.png - -You can also explore the Zipkin dependency UI to view relationships between nodes and the path of traces. - -.. image:: /start/sandboxes/_include/zipkin/_static/zipkin-ui-dependency.png - -.. seealso:: - - :ref:`Request tracing ` - Learn more about using Envoy's request tracing. - - `Zipkin `_ - Zipkin tracing website. diff --git a/examples/zipkin/verify.sh b/examples/zipkin/verify.sh deleted file mode 100755 index 0744d0a41be8..000000000000 --- a/examples/zipkin/verify.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e - -export NAME=zipkin -export PORT_PROXY="${ZIPKIN_PORT_PROXY:-12600}" -export PORT_UI="${ZIPKIN_PORT_UI:-12601}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Make a request to service-1" -responds_with \ - "Hello from behind Envoy (service 1)!" \ - "http://localhost:${PORT_PROXY}/trace/1" - -run_log "Make a request to service-2" -responds_with \ - "Hello from behind Envoy (service 2)!" \ - "http://localhost:${PORT_PROXY}/trace/2" - -run_log "View the traces in Zipkin UI" -responds_with \ - "" \ - "http://localhost:${PORT_UI}/zipkin/" diff --git a/examples/zstd/README.md b/examples/zstd/README.md deleted file mode 100644 index cd7f3bf4884f..000000000000 --- a/examples/zstd/README.md +++ /dev/null @@ -1,2 +0,0 @@ -To learn about this sandbox and for instructions on how to run it please head over -to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/zstd.html) diff --git a/examples/zstd/docker-compose.yaml b/examples/zstd/docker-compose.yaml deleted file mode 100644 index a37faeb6f2cc..000000000000 --- a/examples/zstd/docker-compose.yaml +++ /dev/null @@ -1,15 +0,0 @@ -services: - - envoy-stats: - build: - context: . - dockerfile: ../shared/envoy/Dockerfile - ports: - - "${PORT_PROXY:-10000}:10000" - - "${PORT_ADMIN0:-9901}:9901" - - "${PORT_ADMIN1:-9902}:9902" - - service: - build: - context: ../shared/python - target: aiohttp-data-service diff --git a/examples/zstd/envoy.yaml b/examples/zstd/envoy.yaml deleted file mode 100644 index b3862468db75..000000000000 --- a/examples/zstd/envoy.yaml +++ /dev/null @@ -1,238 +0,0 @@ -static_resources: - listeners: - - address: - socket_address: - address: 0.0.0.0 - port_value: 10000 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/" - route: - cluster: service - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - application/json - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.zstd.compressor.v3.Zstd - compression_level: 10 - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/zstd-key.pem -out a/zstd-crt.pem -days 3650 -nodes -subj '/CN=zstd' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - address: - socket_address: - address: 0.0.0.0 - port_value: 9902 - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: - - "*" - routes: - - match: - prefix: "/stats/prometheus" - route: - cluster: envoy-stats - http_filters: - - name: envoy.filters.http.compressor - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor - response_direction_config: - common_config: - min_content_length: 100 - content_type: - - text/plain - disable_on_etag_header: true - compressor_library: - name: text_optimized - typed_config: - "@type": type.googleapis.com/envoy.extensions.compression.zstd.compressor.v3.Zstd - compression_level: 10 - - name: envoy.filters.http.router - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - transport_socket: - name: envoy.transport_sockets.tls - typed_config: - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext - common_tls_context: - tls_certificates: - # The following self-signed certificate pair is generated using: - # $ openssl req -x509 -newkey rsa:2048 -keyout a/zstd.pem -out a/zstd-crt.pem -days 3650 -nodes -subj '/CN=zstd' - # - # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy - # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. - # - # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via - # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret. - - certificate_chain: - inline_string: | - -----BEGIN CERTIFICATE----- - MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm - cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS - BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC - AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou - oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ - VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt - ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh - 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX - 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg - vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N - v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ - Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 - zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe - 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I - m+/R4XnmL4cKQ+5Z - -----END CERTIFICATE----- - private_key: - inline_string: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD - tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 - VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg - Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj - zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ - oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw - tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB - NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx - lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx - DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 - 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO - eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL - xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 - e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO - mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR - nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB - xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO - EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R - JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 - XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg - +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK - 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 - DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 - o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 - ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU - q5sGxGrC1RECGB5Zwx2S2ZY= - -----END PRIVATE KEY----- - - clusters: - - name: envoy-stats - connect_timeout: 0.25s - type: STATIC - load_assignment: - cluster_name: envoy-stats - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: 127.0.0.1 - port_value: 9901 - - name: service - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: service - port_value: 8080 -admin: - address: - socket_address: - address: 0.0.0.0 - port_value: 9901 diff --git a/examples/zstd/example.rst b/examples/zstd/example.rst deleted file mode 100644 index a44773c3c539..000000000000 --- a/examples/zstd/example.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. _install_sandboxes_zstd: - -Zstd -====== - -.. sidebar:: Requirements - - .. include:: _include/docker-env-setup-link.rst - - :ref:`curl ` - Used to make ``HTTP`` requests. - -By enabling compression in Envoy you can save some network bandwidth, at the expense of increased processor usage. - -Envoy supports compression and decompression for both requests and responses. - -This sandbox provides an example of response compression served over ``HTTPS``. - -The sandbox covers two scenarios: - -- compression of files from an upstream server -- compression of Envoy's own statistics - -Step 1: Start all of our containers -*********************************** - -Change to the ``examples/zstd`` directory and bring up the docker composition. - -.. code-block:: console - - $ pwd - envoy/examples/zstd - $ docker compose pull - $ docker compose up --build -d - $ docker compose ps - Name Command State Ports - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - zstd_envoy-stats_1 /docker-entrypoint.sh /usr ... Up 0.0.0.0:10000->10000/tcp,:::10000->10000/tcp, 0.0.0.0:9901->9901/tcp,:::9901->9901/tcp, 0.0.0.0:9902->9902/tcp,:::9902->9902/tcp - zstd_service_1 python3 /code/service.py Up - -Step 2: Test Envoy’s compression of upstream files -************************************************** - -The sandbox is configured with two endpoints on port ``10000`` for serving upstream files: - -- ``/file.txt`` -- ``/file.json`` - -Only ``/file.json`` is configured to be compressed. - -Use ``curl`` to check that the response from requesting ``file.json`` contains the ``content-encoding: zstd`` header. - -You will need to add an ``accept-encoding: zstd`` request header. - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: zstd" https://localhost:10000/file.json | grep "content-encoding" - content-encoding: zstd - -As only files with a content-type of ``application/json`` are configured to be compressed, the response from requesting ``file.txt`` should not contain the ``content-encoding: zstd`` header, and the file will not be compressed: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: zstd" https://localhost:10000/file.txt | grep "content-encoding" - -Step 3: Test compression of Envoy’s statistics -********************************************** - -The sandbox is configured with two ports serving Envoy’s admin and statistics interface: - -- ``9901`` exposes the standard admin interface without tls -- ``9902`` exposes a compressed version of the admin interface with tls - -Use ``curl`` to make a request for uncompressed statistics on port ``9901``, it should not contain the ``content-encoding`` header in the response: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: zstd" http://localhost:9901/stats/prometheus | grep "content-encoding" - -Now, use ``curl`` to make a request for the compressed statistics: - -.. code-block:: console - - $ curl -ski -H "Accept-Encoding: zstd" https://localhost:9902/stats/prometheus | grep "content-encoding" - content-encoding: zstd - -.. seealso:: - :ref:`Zstd API ` - API and configuration reference for Envoy's zstd compression. - - :ref:`Compression configuration ` - Reference documentation for Envoy's compressor filter. - - :ref:`Envoy admin quick start guide ` - Quick start guide to the Envoy admin interface. diff --git a/examples/zstd/verify.sh b/examples/zstd/verify.sh deleted file mode 100755 index 0437e2f1d69c..000000000000 --- a/examples/zstd/verify.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -export NAME=zstd -export PORT_PROXY="${ZSTD_PORT_PROXY:-12610}" -export PORT_ADMIN0="${ZSTD_PORT_ADMIN0:-12611}" -export PORT_ADMIN1="${ZSTD_PORT_ADMIN1:-12612}" - -# shellcheck source=examples/verify-common.sh -. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" - -run_log "Test service: localhost:${PORT_PROXY}/file.json with compression" -responds_with_header \ - "content-encoding: zstd" \ - "https://localhost:${PORT_PROXY}/file.json" \ - -ki -H "Accept-Encoding: zstd" - -run_log "Test service: localhost:${PORT_PROXY}/file.txt without compression" -responds_without_header \ - "content-encoding: zstd" \ - "https://localhost:${PORT_PROXY}/file.txt" \ - -ki -H "Accept-Encoding: zstd" - -run_log "Test service: localhost:${PORT_ADMIN0}/stats/prometheus without compression" -responds_without_header \ - "content-encoding: zstd" \ - "http://localhost:${PORT_ADMIN0}/stats/prometheus" \ - -ki -H "Accept-Encoding: zstd" - -run_log "Test service: localhost:${PORT_ADMIN1}/stats/prometheus with compression" -responds_with_header \ - "content-encoding: zstd" \ - "https://localhost:${PORT_ADMIN1}/stats/prometheus" \ - -ki -H "Accept-Encoding: zstd" diff --git a/mobile/WORKSPACE b/mobile/WORKSPACE index cdb172f0cd24..84ee61649ac2 100644 --- a/mobile/WORKSPACE +++ b/mobile/WORKSPACE @@ -46,6 +46,10 @@ load("@envoy//bazel:api_repositories.bzl", "envoy_api_dependencies") envoy_api_dependencies() +load("@envoy//bazel:repo.bzl", "envoy_repo") + +envoy_repo() + load("@envoy//bazel:repositories.bzl", "envoy_dependencies") envoy_dependencies() diff --git a/mobile/library/cc/engine_builder.cc b/mobile/library/cc/engine_builder.cc index dde68d120c63..ac4cb04e13f5 100644 --- a/mobile/library/cc/engine_builder.cc +++ b/mobile/library/cc/engine_builder.cc @@ -760,6 +760,7 @@ std::unique_ptr EngineBuilder::generate list->add_patterns()->set_prefix("cluster.base.upstream_cx_"); list->add_patterns()->set_prefix("cluster.stats.upstream_cx_"); list->add_patterns()->set_exact("cluster.base.http2.keepalive_timeout"); + list->add_patterns()->set_exact("cluster.base.upstream_http3_broken"); list->add_patterns()->set_exact("cluster.stats.http2.keepalive_timeout"); list->add_patterns()->set_prefix("http.hcm.downstream_rq_"); list->add_patterns()->set_prefix("http.hcm.decompressor."); diff --git a/mobile/library/common/extensions/listener_managers/api_listener_manager/api_listener_manager.cc b/mobile/library/common/extensions/listener_managers/api_listener_manager/api_listener_manager.cc index 8a4f04320cbe..c89d321179b8 100644 --- a/mobile/library/common/extensions/listener_managers/api_listener_manager/api_listener_manager.cc +++ b/mobile/library/common/extensions/listener_managers/api_listener_manager/api_listener_manager.cc @@ -37,7 +37,7 @@ ApiListenerManagerImpl::addOrUpdateListener(const envoy::config::listener::v3::L } if (!api_listener_ && !added_via_api) { auto listener_or_error = HttpApiListener::create(config, server_, config.name()); - RETURN_IF_STATUS_NOT_OK(listener_or_error); + RETURN_IF_NOT_OK(listener_or_error.status()); api_listener_ = std::move(listener_or_error.value()); return true; } else { diff --git a/mobile/library/common/http/header_utility.cc b/mobile/library/common/http/header_utility.cc index b97da27b0f60..fc1ae9ec0e56 100644 --- a/mobile/library/common/http/header_utility.cc +++ b/mobile/library/common/http/header_utility.cc @@ -9,14 +9,9 @@ namespace Envoy { namespace Http { namespace Utility { -Http::LocalErrorStatus statusForOnLocalReply(const StreamDecoderFilter::LocalReplyData& reply, - const StreamInfo::StreamInfo& info) { - // This is a horrible hack to work around legacy swift direct response API. - // TODO(https://github.com/envoyproxy/envoy/issues/24428) remove. - if (reply.details_ == "direct_response" && info.getRequestHeaders() && - info.getRequestHeaders()->getHostValue() == "127.0.0.1") { - return Http::LocalErrorStatus::Continue; - } +Http::LocalErrorStatus statusForOnLocalReply(const StreamDecoderFilter::LocalReplyData&, + const StreamInfo::StreamInfo&) { + // Avoid sendLocalReply to differentiate Envoy generated errors from peer generated errors. return Http::LocalErrorStatus::ContinueAndResetStream; } diff --git a/mobile/library/common/internal_engine.cc b/mobile/library/common/internal_engine.cc index 587613480e30..c5b774cda157 100644 --- a/mobile/library/common/internal_engine.cc +++ b/mobile/library/common/internal_engine.cc @@ -5,6 +5,7 @@ #include "source/common/api/os_sys_calls_impl.h" #include "source/common/common/lock_guard.h" #include "source/common/common/utility.h" +#include "source/common/http/http_server_properties_cache_manager_impl.h" #include "source/common/network/io_socket_handle_impl.h" #include "source/common/runtime/runtime_features.h" @@ -16,6 +17,7 @@ namespace { constexpr absl::Duration ENGINE_RUNNING_TIMEOUT = absl::Seconds(30); // Google DNS address used for IPv6 probes. constexpr absl::string_view IPV6_PROBE_ADDRESS = "2001:4860:4860::8888"; +constexpr uint32_t IPV6_PROBE_PORT = 53; } // namespace static std::atomic current_stream_handle_{0}; @@ -294,6 +296,15 @@ envoy_status_t InternalEngine::setPreferredNetwork(NetworkType network) { connectivity_manager_->dnsCache()->setIpVersionToRemove(absl::nullopt); } } + if (Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.reset_brokenness_on_nework_change")) { + Http::HttpServerPropertiesCacheManager& cache_manager = + server_->httpServerPropertiesCacheManager(); + + Http::HttpServerPropertiesCacheManager::CacheFn clear_brokenness = + [](Http::HttpServerPropertiesCache& cache) { cache.resetBrokenness(); }; + cache_manager.forEachThreadLocalCache(clear_brokenness); + } connectivity_manager_->refreshDns(configuration_key, true); }); } @@ -415,8 +426,9 @@ bool InternalEngine::hasIpV6Connectivity() { } Network::IoSocketHandleImpl socket_handle(socket_result.return_value_, /* socket_v6only= */ true, {domain}); - Api::SysCallIntResult connect_result = socket_handle.connect( - std::make_shared(std::string(IPV6_PROBE_ADDRESS))); + Api::SysCallIntResult connect_result = + socket_handle.connect(std::make_shared( + std::string(IPV6_PROBE_ADDRESS), IPV6_PROBE_PORT)); bool has_ipv6_connectivity = connect_result.return_value_ == 0; if (has_ipv6_connectivity) { ENVOY_LOG(trace, "Found IPv6 connectivity."); diff --git a/mobile/library/common/internal_engine.h b/mobile/library/common/internal_engine.h index 7a977d56f609..4b7ab545ccf6 100644 --- a/mobile/library/common/internal_engine.h +++ b/mobile/library/common/internal_engine.h @@ -115,6 +115,7 @@ class InternalEngine : public Logger::Loggable { * `setIpVersionToRemove` in the DNS cache implementation to remove the IPv6 addresses from * the DNS response in the subsequent DNS resolutions. * - Force refresh the hosts in the DNS cache (will take `setIpVersionToRemove` into account). + * - Optionally (if configured) clear HTTP/3 broken status. */ envoy_status_t setPreferredNetwork(NetworkType network); diff --git a/mobile/library/jni/android_jni_utility.cc b/mobile/library/jni/android_jni_utility.cc index 6d39da3cd814..62e65a7c3a0a 100644 --- a/mobile/library/jni/android_jni_utility.cc +++ b/mobile/library/jni/android_jni_utility.cc @@ -16,8 +16,8 @@ bool isCleartextPermitted(absl::string_view hostname) { JniHelper jni_helper(JniHelper::getThreadLocalEnv()); LocalRefUniquePtr java_host = cppStringToJavaString(jni_helper, std::string(hostname)); jclass java_android_network_library_class = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - jmethodID java_is_cleartext_traffic_permitted_method_id = jni_helper.getStaticMethodId( + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); + jmethodID java_is_cleartext_traffic_permitted_method_id = jni_helper.getStaticMethodIdFromCache( java_android_network_library_class, "isCleartextTrafficPermitted", "(Ljava/lang/String;)Z"); jboolean result = jni_helper.callStaticBooleanMethod( java_android_network_library_class, java_is_cleartext_traffic_permitted_method_id, @@ -33,9 +33,9 @@ void tagSocket(int ifd, int uid, int tag) { #if defined(__ANDROID_API__) JniHelper jni_helper(JniHelper::getThreadLocalEnv()); jclass java_android_network_library_class = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - jmethodID java_tag_socket_method_id = - jni_helper.getStaticMethodId(java_android_network_library_class, "tagSocket", "(III)V"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); + jmethodID java_tag_socket_method_id = jni_helper.getStaticMethodIdFromCache( + java_android_network_library_class, "tagSocket", "(III)V"); jni_helper.callStaticVoidMethod(java_android_network_library_class, java_tag_socket_method_id, ifd, uid, tag); #else diff --git a/mobile/library/jni/android_network_utility.cc b/mobile/library/jni/android_network_utility.cc index e418ffd6cdee..988c03a5d982 100644 --- a/mobile/library/jni/android_network_utility.cc +++ b/mobile/library/jni/android_network_utility.cc @@ -35,9 +35,9 @@ enum class CertVerifyStatus : int { bool jvmCertIsIssuedByKnownRoot(JniHelper& jni_helper, jobject result) { jclass jcls_AndroidCertVerifyResult = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); jmethodID jmid_isIssuedByKnownRoot = - jni_helper.getMethodId(jcls_AndroidCertVerifyResult, "isIssuedByKnownRoot", "()Z"); + jni_helper.getMethodIdFromCache(jcls_AndroidCertVerifyResult, "isIssuedByKnownRoot", "()Z"); ASSERT(jmid_isIssuedByKnownRoot); bool is_issued_by_known_root = jni_helper.callBooleanMethod(result, jmid_isIssuedByKnownRoot); return is_issued_by_known_root; @@ -45,9 +45,9 @@ bool jvmCertIsIssuedByKnownRoot(JniHelper& jni_helper, jobject result) { CertVerifyStatus jvmCertGetStatus(JniHelper& jni_helper, jobject j_result) { jclass jcls_AndroidCertVerifyResult = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); jmethodID jmid_getStatus = - jni_helper.getMethodId(jcls_AndroidCertVerifyResult, "getStatus", "()I"); + jni_helper.getMethodIdFromCache(jcls_AndroidCertVerifyResult, "getStatus", "()I"); ASSERT(jmid_getStatus); CertVerifyStatus result = static_cast(jni_helper.callIntMethod(j_result, jmid_getStatus)); @@ -57,9 +57,9 @@ CertVerifyStatus jvmCertGetStatus(JniHelper& jni_helper, jobject j_result) { LocalRefUniquePtr jvmCertGetCertificateChainEncoded(JniHelper& jni_helper, jobject result) { jclass jcls_AndroidCertVerifyResult = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); - jmethodID jmid_getCertificateChainEncoded = - jni_helper.getMethodId(jcls_AndroidCertVerifyResult, "getCertificateChainEncoded", "()[[B"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); + jmethodID jmid_getCertificateChainEncoded = jni_helper.getMethodIdFromCache( + jcls_AndroidCertVerifyResult, "getCertificateChainEncoded", "()[[B"); LocalRefUniquePtr certificate_chain = jni_helper.callObjectMethod(result, jmid_getCertificateChainEncoded); return certificate_chain; @@ -108,8 +108,8 @@ LocalRefUniquePtr callJvmVerifyX509CertChain(JniHelper& jni_helper, std::string auth_type, absl::string_view hostname) { jclass jcls_AndroidNetworkLibrary = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - jmethodID jmid_verifyServerCertificates = jni_helper.getStaticMethodId( + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); + jmethodID jmid_verifyServerCertificates = jni_helper.getStaticMethodIdFromCache( jcls_AndroidNetworkLibrary, "verifyServerCertificates", "([[B[B[B)Lio/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult;"); LocalRefUniquePtr chain_byte_array = diff --git a/mobile/library/jni/jni_helper.cc b/mobile/library/jni/jni_helper.cc index 1dd285e1116b..67dfd1aa9d4f 100644 --- a/mobile/library/jni/jni_helper.cc +++ b/mobile/library/jni/jni_helper.cc @@ -19,44 +19,19 @@ thread_local JNIEnv* jni_env_cache_ = nullptr; // `jclass_cache_map` contains `jclass` references that are statically populated. This field is // used by `FindClass` to find the `jclass` reference from a given class name. absl::flat_hash_map jclass_cache_map; -// The `jclass_cache_set` is a superset of `jclass_cache_map`. It contains `jclass` objects that are -// retrieve dynamically via `GetObjectClass`. -// -// The `jclass_cache_set` owns the `jclass` global refs, wrapped in `GlobalRefUniquePtr` to allow -// automatic `GlobalRef` destruction. The other fields, such as `jmethod_id_cache_map`, -// `static_jmethod_id_cache_map`, `jfield_id_cache_map`, and `static_jfield_id_cache_map` only -// borrow the `jclass` references. -// -// Note: all these fields are `thread_local` to avoid locking. -thread_local absl::flat_hash_set> jclass_cache_set; -thread_local absl::flat_hash_map< +absl::flat_hash_map< std::tuple, jmethodID> jmethod_id_cache_map; -thread_local absl::flat_hash_map< - std::tuple, - jmethodID /* signature */> +absl::flat_hash_map, + jmethodID /* signature */> static_jmethod_id_cache_map; -thread_local absl::flat_hash_map< - std::tuple, jfieldID /* signature */> +absl::flat_hash_map, + jfieldID /* signature */> jfield_id_cache_map; -thread_local absl::flat_hash_map< - std::tuple, jfieldID /* signature */> +absl::flat_hash_map, + jfieldID /* signature */> static_jfield_id_cache_map; - -/** - * This function checks if the `clazz` already exists in the `jclass` `GlobalRef` cache and creates - * a new `GlobalRef` if it does not already exist. This functions returns the `GlobalRef` of the - * specified `clazz`. - */ -jclass addClassToCacheIfNotExist(JNIEnv* env, jclass clazz) { - jclass java_class_global_ref = clazz; - if (auto it = jclass_cache_set.find(clazz); it == jclass_cache_set.end()) { - java_class_global_ref = reinterpret_cast(env->NewGlobalRef(clazz)); - jclass_cache_set.emplace(java_class_global_ref, GlobalRefDeleter()); - } - return java_class_global_ref; -} } // namespace void GlobalRefDeleter::operator()(jobject object) const { @@ -99,21 +74,67 @@ void JniHelper::finalize() { jfield_id_cache_map.clear(); static_jfield_id_cache_map.clear(); jclass_cache_map.clear(); - for (const auto& clazz : jclass_cache_set) { - env->DeleteGlobalRef(clazz.get()); + for (const auto& [_, clazz] : jclass_cache_map) { + env->DeleteGlobalRef(clazz); } - jclass_cache_set.clear(); } -void JniHelper::addClassToCache(const char* class_name) { +void JniHelper::addToCache(absl::string_view class_name, const std::vector& methods, + const std::vector& static_methods, + const std::vector& fields, + const std::vector& static_fields) { JNIEnv* env; jint result = getJavaVm()->GetEnv(reinterpret_cast(&env), getVersion()); ASSERT(result == JNI_OK, "Unable to get JNIEnv from the JavaVM."); - jclass java_class = env->FindClass(class_name); + jclass java_class = env->FindClass(class_name.data()); ASSERT(java_class != nullptr, absl::StrFormat("Unable to find class '%s'.", class_name)); jclass java_class_global_ref = reinterpret_cast(env->NewGlobalRef(java_class)); jclass_cache_map.emplace(class_name, java_class_global_ref); - jclass_cache_set.emplace(java_class_global_ref, GlobalRefDeleter()); + + for (const auto& [method_name, signature] : methods) { + jmethodID method_id = + env->GetMethodID(java_class_global_ref, method_name.data(), signature.data()); + ASSERT(method_id != nullptr, + absl::StrFormat("Unable to find method ID for class '%s', method '%s', signature '%s'.", + class_name, method_name, signature)); + jmethod_id_cache_map.emplace(std::tuple( + java_class_global_ref, method_name, signature), + method_id); + } + + for (const auto& [method_name, signature] : static_methods) { + jmethodID method_id = + env->GetStaticMethodID(java_class_global_ref, method_name.data(), signature.data()); + ASSERT(method_id != nullptr, + absl::StrFormat( + "Unable to find static method ID for class '%s', method '%s', signature '%s'.", + class_name, method_name, signature)); + static_jmethod_id_cache_map.emplace(std::tuple( + java_class_global_ref, method_name, signature), + method_id); + } + + for (const auto& [field_name, signature] : fields) { + jfieldID field_id = env->GetFieldID(java_class_global_ref, field_name.data(), signature.data()); + ASSERT(field_id != nullptr, + absl::StrFormat("Unable to find field ID for class '%s', field '%s', signature '%s'.", + class_name, field_name, signature)); + jfield_id_cache_map.emplace(std::tuple( + java_class_global_ref, field_name, signature), + field_id); + } + + for (const auto& [field_name, signature] : static_fields) { + jfieldID field_id = + env->GetStaticFieldID(java_class_global_ref, field_name.data(), signature.data()); + ASSERT(field_id != nullptr, + absl::StrFormat( + "Unable to find static field ID for class '%s', field '%s', signature '%s'.", + class_name, field_name, signature)); + static_jfield_id_cache_map.emplace(std::tuple( + java_class_global_ref, field_name, signature), + field_id); + } } JavaVM* JniHelper::getJavaVm() { return java_vm_cache_.load(std::memory_order_acquire); } @@ -141,33 +162,45 @@ JNIEnv* JniHelper::getThreadLocalEnv() { JNIEnv* JniHelper::getEnv() { return env_; } jfieldID JniHelper::getFieldId(jclass clazz, const char* name, const char* signature) { + jfieldID field_id = env_->GetFieldID(clazz, name, signature); + rethrowException(); + return field_id; +} + +jfieldID JniHelper::getFieldIdFromCache(jclass clazz, const char* name, const char* signature) { if (auto it = jfield_id_cache_map.find( std::tuple(clazz, name, signature)); it != jfield_id_cache_map.end()) { return it->second; } - jfieldID field_id = env_->GetFieldID(clazz, name, signature); - jclass clazz_global_ref = addClassToCacheIfNotExist(env_, clazz); - jfield_id_cache_map.emplace( - std::tuple(clazz_global_ref, name, signature), - field_id); + // In the debug mode, the code will fail if the field ID is not in the cache since this is most + // likely due to a bug in the code. In the release mode, the code will use the non-caching field + // ID. + ASSERT(false, absl::StrFormat("Unable to find field ID '%s', signature '%s' from the cache.", + name, signature)); + return getFieldId(clazz, name, signature); +} + +jfieldID JniHelper::getStaticFieldId(jclass clazz, const char* name, const char* signature) { + jfieldID field_id = env_->GetStaticFieldID(clazz, name, signature); rethrowException(); return field_id; } -jfieldID JniHelper::getStaticFieldId(jclass clazz, const char* name, const char* signature) { +jfieldID JniHelper::getStaticFieldIdFromCache(jclass clazz, const char* name, + const char* signature) { if (auto it = static_jfield_id_cache_map.find( std::tuple(clazz, name, signature)); it != static_jfield_id_cache_map.end()) { return it->second; } - jfieldID field_id = env_->GetStaticFieldID(clazz, name, signature); - jclass clazz_global_ref = addClassToCacheIfNotExist(env_, clazz); - static_jfield_id_cache_map.emplace( - std::tuple(clazz_global_ref, name, signature), - field_id); - rethrowException(); - return field_id; + // In the debug mode, the code will fail if the static field ID is not in the cache since this is + // most likely due to a bug in the code. In the release mode, the code will use the non-caching + // static field ID. + ASSERT(false, + absl::StrFormat("Unable to find static field ID '%s', signature '%s' from the cache.", + name, signature)); + return getStaticFieldId(clazz, name, signature); } #define DEFINE_GET_FIELD(JAVA_TYPE, JNI_TYPE) \ @@ -185,41 +218,55 @@ DEFINE_GET_FIELD(Double, jdouble) DEFINE_GET_FIELD(Boolean, jboolean) jmethodID JniHelper::getMethodId(jclass clazz, const char* name, const char* signature) { + jmethodID method_id = env_->GetMethodID(clazz, name, signature); + rethrowException(); + return method_id; +} + +jmethodID JniHelper::getMethodIdFromCache(jclass clazz, const char* name, const char* signature) { if (auto it = jmethod_id_cache_map.find( std::tuple(clazz, name, signature)); it != jmethod_id_cache_map.end()) { return it->second; } - jmethodID method_id = env_->GetMethodID(clazz, name, signature); - jclass clazz_global_ref = addClassToCacheIfNotExist(env_, clazz); - jmethod_id_cache_map.emplace( - std::tuple(clazz_global_ref, name, signature), - method_id); + // In the debug mode, the code will fail if the method ID is not in the cache since this is most + // likely due to a bug in the code. In the release mode, the code will use the non-caching method + // ID. + ASSERT(false, absl::StrFormat("Unable to find method ID '%s', signature '%s' from the cache.", + name, signature)); + return getMethodId(clazz, name, signature); +} + +jmethodID JniHelper::getStaticMethodId(jclass clazz, const char* name, const char* signature) { + jmethodID method_id = env_->GetStaticMethodID(clazz, name, signature); rethrowException(); return method_id; } -jmethodID JniHelper::getStaticMethodId(jclass clazz, const char* name, const char* signature) { +jmethodID JniHelper::getStaticMethodIdFromCache(jclass clazz, const char* name, + const char* signature) { if (auto it = static_jmethod_id_cache_map.find( std::tuple(clazz, name, signature)); it != static_jmethod_id_cache_map.end()) { return it->second; } - jmethodID method_id = env_->GetStaticMethodID(clazz, name, signature); - jclass clazz_global_ref = addClassToCacheIfNotExist(env_, clazz); - static_jmethod_id_cache_map.emplace( - std::tuple(clazz_global_ref, name, signature), - method_id); - rethrowException(); - return method_id; + // In the debug mode, the code will fail if the static method ID is not in the cache since this is + // most likely due to a bug in the code. In the release mode, the code will use the non-caching + // static method ID. + ASSERT(false, + absl::StrFormat("Unable to find static method ID '%s', signature '%s' from the cache.", + name, signature)); + return getStaticMethodId(clazz, name, signature); } -jclass JniHelper::findClass(const char* class_name) { +jclass JniHelper::findClassFromCache(const char* class_name) { if (auto i = jclass_cache_map.find(class_name); i != jclass_cache_map.end()) { return i->second; } + // In the debug mode, the code will fail if the class is not in the cache since this is most + // likely due to a bug in the code. In the release mode, the code will use the non-caching class. ASSERT(false, absl::StrFormat("Unable to find class '%s'.", class_name)); - return nullptr; + return env_->FindClass(class_name); } LocalRefUniquePtr JniHelper::getObjectClass(jobject object) { @@ -227,7 +274,7 @@ LocalRefUniquePtr JniHelper::getObjectClass(jobject object) { } void JniHelper::throwNew(const char* java_class_name, const char* message) { - jclass java_class = findClass(java_class_name); + jclass java_class = findClassFromCache(java_class_name); if (java_class != nullptr) { jint error = env_->ThrowNew(java_class, message); ASSERT(error == JNI_OK, "Failed calling ThrowNew."); diff --git a/mobile/library/jni/jni_helper.h b/mobile/library/jni/jni_helper.h index cb3b07f20b84..82898283a421 100644 --- a/mobile/library/jni/jni_helper.h +++ b/mobile/library/jni/jni_helper.h @@ -4,6 +4,8 @@ #include +#include "absl/strings/string_view.h" + namespace Envoy { namespace JNI { @@ -119,6 +121,16 @@ class JniHelper { public: explicit JniHelper(JNIEnv* env) : env_(env) {} + struct Method { + absl::string_view name_; + absl::string_view signature_; + }; + + struct Field { + absl::string_view name_; + absl::string_view signature_; + }; + /** Gets the JNI version supported. */ static jint getVersion(); @@ -129,7 +141,8 @@ class JniHelper { static void finalize(); /** - * Adds the `jclass` object into a cache. This function is typically called inside `JNI_OnLoad`. + * Adds the `jclass`, `jmethodID`, and `jfieldID` objects into a cache. This function is typically + * called inside `JNI_OnLoad`. * * Caching the `jclass` can be useful for performance. * See https://developer.android.com/training/articles/perf-jni#jclass,-jmethodid,-and-jfieldid @@ -144,7 +157,9 @@ class JniHelper { * See * https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class */ - static void addClassToCache(const char* class_name); + static void addToCache(absl::string_view class_name, const std::vector& methods, + const std::vector& static_methods, + const std::vector& fields, const std::vector& static_fields); /** Gets the `JavaVM`. The `initialize(JavaVM*) must be called first. */ static JavaVM* getJavaVm(); @@ -174,6 +189,13 @@ class JniHelper { */ jfieldID getFieldId(jclass clazz, const char* name, const char* signature); + /** + * Gets the field ID for an instance field of a class from the cache. + * + * https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html#getfieldid + */ + jfieldID getFieldIdFromCache(jclass clazz, const char* name, const char* signature); + /** * Gets the field ID for a static field of a class. * @@ -181,6 +203,13 @@ class JniHelper { */ jfieldID getStaticFieldId(jclass clazz, const char* name, const char* signature); + /** + * Gets the field ID for a static field of a class from the cache. + * + * https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html#getstaticfieldid + */ + jfieldID getStaticFieldIdFromCache(jclass clazz, const char* name, const char* signature); + /** A macro to create `CallMethod` helper function. */ #define DECLARE_GET_FIELD(JAVA_TYPE, JNI_TYPE) \ JNI_TYPE get##JAVA_TYPE##Field(jobject object, jfieldID field_id); @@ -213,6 +242,13 @@ class JniHelper { */ jmethodID getMethodId(jclass clazz, const char* name, const char* signature); + /** + * Gets the object method with the given signature from the cache. + * + * https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html#getmethodid + */ + jmethodID getMethodIdFromCache(jclass clazz, const char* name, const char* signature); + /** * Gets the static method with the given signature. * @@ -220,12 +256,19 @@ class JniHelper { */ jmethodID getStaticMethodId(jclass clazz, const char* name, const char* signature); + /** + * Gets the static method with the given signature from the cache. + * + * https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html#getstaticmethodid + */ + jmethodID getStaticMethodIdFromCache(jclass clazz, const char* name, const char* signature); + /** * Finds the given `class_name` using from the cache. * * https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html#findclass */ - [[nodiscard]] jclass findClass(const char* class_name); + [[nodiscard]] jclass findClassFromCache(const char* class_name); /** * Returns the class of a given `object`. diff --git a/mobile/library/jni/jni_impl.cc b/mobile/library/jni/jni_impl.cc index 847182a8c241..0e0c21d17e93 100644 --- a/mobile/library/jni/jni_impl.cc +++ b/mobile/library/jni/jni_impl.cc @@ -21,25 +21,72 @@ using Envoy::Platform::EngineBuilder; extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { Envoy::JNI::JniHelper::initialize(vm); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Object"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Integer"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/ClassLoader"); - Envoy::JNI::JniHelper::addClassToCache("java/nio/ByteBuffer"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Throwable"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/UnsupportedOperationException"); - Envoy::JNI::JniHelper::addClassToCache("[B"); - Envoy::JNI::JniHelper::addClassToCache("java/util/Map$Entry"); - Envoy::JNI::JniHelper::addClassToCache("java/util/LinkedHashMap"); - Envoy::JNI::JniHelper::addClassToCache("java/util/HashMap"); - Envoy::JNI::JniHelper::addClassToCache("java/util/List"); - Envoy::JNI::JniHelper::addClassToCache("java/util/ArrayList"); - Envoy::JNI::JniHelper::addClassToCache("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult"); + Envoy::JNI::JniUtility::initCache(); + Envoy::JNI::JniHelper::addToCache( + "io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary", + /* methods= */ {}, + /* static_methods= */ + { + {"isCleartextTrafficPermitted", "(Ljava/lang/String;)Z"}, + {"tagSocket", "(III)V"}, + {"verifyServerCertificates", + "([[B[B[B)Lio/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult;"}, + {"addTestRootCertificate", "([B)V"}, + {"clearTestRootCertificates", "()V"}, + + }, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult", + /* methods= */ + { + {"isIssuedByKnownRoot", "()Z"}, + {"getStatus", "()I"}, + {"getCertificateChainEncoded", "()[[B"}, + }, + /* static_methods= */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/engine/types/EnvoyOnEngineRunning", + /* methods= */ + { + {"invokeOnEngineRunning", "()Ljava/lang/Object;"}, + }, + /* static_methods= */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/engine/types/EnvoyLogger", + /* methods= */ + { + {"log", "(ILjava/lang/String;)V"}, + }, + /* static_methods= */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/engine/types/EnvoyEventTracker", + /* methods= */ + { + {"track", "(Ljava/util/Map;)V"}, + }, + /* static_methods= */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks", + /* methods= */ + { + {"onHeaders", + "(Ljava/util/Map;ZLio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"}, + {"onData", + "(Ljava/nio/ByteBuffer;ZLio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"}, + {"onTrailers", + "(Ljava/util/Map;Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"}, + {"onComplete", "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;Lio/envoyproxy/" + "envoymobile/engine/types/EnvoyFinalStreamIntel;)V"}, + {"onError", + "(ILjava/lang/String;ILio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;Lio/" + "envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"}, + {"onCancel", "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;Lio/envoyproxy/" + "envoymobile/engine/types/EnvoyFinalStreamIntel;)V"}, + {"onSendWindowAvailable", "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"}, + }, + /* static_methods= */ {}, + /* fields= */ {}, /* static_fields= */ {}); return Envoy::JNI::JniHelper::getVersion(); } @@ -63,10 +110,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr jobject on_engine_running_global_ref = env->NewGlobalRef(on_engine_running); callbacks->on_engine_running_ = [on_engine_running_global_ref] { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); - Envoy::JNI::LocalRefUniquePtr java_on_engine_running_class = - jni_helper.getObjectClass(on_engine_running_global_ref); - jmethodID java_on_engine_running_method_id = jni_helper.getMethodId( - java_on_engine_running_class.get(), "invokeOnEngineRunning", "()Ljava/lang/Object;"); + auto java_on_engine_running_class = jni_helper.findClassFromCache( + "io/envoyproxy/envoymobile/engine/types/EnvoyOnEngineRunning"); + jmethodID java_on_engine_running_method_id = jni_helper.getMethodIdFromCache( + java_on_engine_running_class, "invokeOnEngineRunning", "()Ljava/lang/Object;"); Envoy::JNI::LocalRefUniquePtr unused = jni_helper.callObjectMethod( on_engine_running_global_ref, java_on_engine_running_method_id); jni_helper.getEnv()->DeleteGlobalRef(on_engine_running_global_ref); @@ -91,10 +138,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr Envoy::JNI::LocalRefUniquePtr java_message = Envoy::JNI::cppStringToJavaString(jni_helper, message); jint java_level = static_cast(level); - Envoy::JNI::LocalRefUniquePtr java_envoy_logger_class = - jni_helper.getObjectClass(envoy_logger_global_ref); + auto java_envoy_logger_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyLogger"); jmethodID java_log_method_id = - jni_helper.getMethodId(java_envoy_logger_class.get(), "log", "(ILjava/lang/String;)V"); + jni_helper.getMethodIdFromCache(java_envoy_logger_class, "log", "(ILjava/lang/String;)V"); jni_helper.callVoidMethod(envoy_logger_global_ref, java_log_method_id, java_level, java_message.get()); }; @@ -114,10 +161,10 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); Envoy::JNI::LocalRefUniquePtr java_events = Envoy::JNI::cppMapToJavaMap(jni_helper, events); - Envoy::JNI::LocalRefUniquePtr java_envoy_event_tracker_class = - jni_helper.getObjectClass(event_tracker_global_ref); - jmethodID java_track_method_id = jni_helper.getMethodId(java_envoy_event_tracker_class.get(), - "track", "(Ljava/util/Map;)V"); + auto java_envoy_event_tracker_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyEventTracker"); + jmethodID java_track_method_id = jni_helper.getMethodIdFromCache( + java_envoy_event_tracker_class, "track", "(Ljava/util/Map;)V"); jni_helper.callVoidMethod(event_tracker_global_ref, java_track_method_id, java_events.get()); }; event_tracker->on_exit_ = [event_tracker_global_ref] { @@ -249,12 +296,12 @@ jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoyHeaders& head // Create a "no operation" result: // 1. Tell the filter chain to continue the iteration. // 2. Return headers received on as method's input as part of the method's output. - jclass jcls_object_array = jni_helper.findClass("java/lang/Object"); + jclass jcls_object_array = jni_helper.findClassFromCache("java/lang/Object"); Envoy::JNI::LocalRefUniquePtr noopResult = jni_helper.newObjectArray(2, jcls_object_array, NULL); - jclass jcls_int = jni_helper.findClass("java/lang/Integer"); - jmethodID jmid_intInit = jni_helper.getMethodId(jcls_int, "", "(I)V"); + jclass jcls_int = jni_helper.findClassFromCache("java/lang/Integer"); + jmethodID jmid_intInit = jni_helper.getMethodIdFromCache(jcls_int, "", "(I)V"); Envoy::JNI::LocalRefUniquePtr j_status = jni_helper.newObject(jcls_int, jmid_intInit, 0); // Set status to "0" (FilterHeadersStatus::Continue). Signal that the intent // is to continue the iteration of the filter chain. @@ -787,9 +834,10 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); auto java_headers = Envoy::JNI::cppHeadersToJavaHeaders(jni_helper, headers); auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_headers_method_id = jni_helper.getMethodId( - java_stream_callbacks_class.get(), "onHeaders", + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_headers_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onHeaders", "(Ljava/util/Map;ZLio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_headers_method_id, java_headers.get(), static_cast(end_stream), @@ -799,12 +847,13 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra const Envoy::Buffer::Instance& buffer, uint64_t length, bool end_stream, envoy_stream_intel stream_intel) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); auto java_byte_buffer = Envoy::JNI::cppBufferInstanceToJavaDirectByteBuffer(jni_helper, buffer, length); auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); - auto java_on_data_method_id = jni_helper.getMethodId( - java_stream_callbacks_class.get(), "onData", + auto java_on_data_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onData", "(Ljava/nio/ByteBuffer;ZLio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_data_method_id, java_byte_buffer.get(), static_cast(end_stream), @@ -816,9 +865,10 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); auto java_trailers = Envoy::JNI::cppHeadersToJavaHeaders(jni_helper, trailers); auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_trailers_method_id = jni_helper.getMethodId( - java_stream_callbacks_class.get(), "onTrailers", + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_trailers_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onTrailers", "(Ljava/util/Map;Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_trailers_method_id, java_trailers.get(), java_stream_intel.get()); @@ -830,11 +880,12 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); auto java_final_stream_intel = Envoy::JNI::cppFinalStreamIntelToJavaFinalStreamIntel(jni_helper, final_stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_complete_method_id = - jni_helper.getMethodId(java_stream_callbacks_class.get(), "onComplete", - "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;" - "Lio/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"); + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_complete_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onComplete", + "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;" + "Lio/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_complete_method_id, java_stream_intel.get(), java_final_stream_intel.get()); // on_complete_ is a terminal callback, delete the java_stream_callbacks_global_ref. @@ -847,9 +898,10 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); auto java_final_stream_intel = Envoy::JNI::cppFinalStreamIntelToJavaFinalStreamIntel(jni_helper, final_stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_error_method_id = jni_helper.getMethodId( - java_stream_callbacks_class.get(), "onError", + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_error_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onError", "(ILjava/lang/String;ILio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;" "Lio/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"); auto java_error_message = Envoy::JNI::cppStringToJavaString(jni_helper, error.message_); @@ -867,11 +919,12 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); auto java_final_stream_intel = Envoy::JNI::cppFinalStreamIntelToJavaFinalStreamIntel(jni_helper, final_stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_cancel_method_id = - jni_helper.getMethodId(java_stream_callbacks_class.get(), "onCancel", - "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;" - "Lio/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"); + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_cancel_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onCancel", + "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;" + "Lio/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_cancel_method_id, java_stream_intel.get(), java_final_stream_intel.get()); // on_cancel_ is a terminal callback, delete the java_stream_callbacks_global_ref. @@ -881,10 +934,11 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra envoy_stream_intel stream_intel) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); auto java_stream_intel = Envoy::JNI::cppStreamIntelToJavaStreamIntel(jni_helper, stream_intel); - auto java_stream_callbacks_class = jni_helper.getObjectClass(java_stream_callbacks_global_ref); - auto java_on_send_window_available_method_id = - jni_helper.getMethodId(java_stream_callbacks_class.get(), "onSendWindowAvailable", - "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"); + auto java_stream_callbacks_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks"); + auto java_on_send_window_available_method_id = jni_helper.getMethodIdFromCache( + java_stream_callbacks_class, "onSendWindowAvailable", + "(Lio/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel;)V"); jni_helper.callVoidMethod(java_stream_callbacks_global_ref, java_on_send_window_available_method_id, java_stream_intel.get()); }; @@ -1323,8 +1377,8 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_callAddTestRootCertificateFromN std::vector cpp_cert; Envoy::JNI::javaByteArrayToByteVector(jni_helper, java_cert, &cpp_cert); jclass java_android_network_library_class = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - jmethodID java_add_test_root_certificate_method_id = jni_helper.getStaticMethodId( + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); + jmethodID java_add_test_root_certificate_method_id = jni_helper.getStaticMethodIdFromCache( java_android_network_library_class, "addTestRootCertificate", "([B)V"); Envoy::JNI::LocalRefUniquePtr cert_array = Envoy::JNI::byteArrayToJavaByteArray(jni_helper, cpp_cert.data(), cpp_cert.size()); @@ -1337,8 +1391,8 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_callClearTestRootCertificateFro jclass) { Envoy::JNI::JniHelper jni_helper(Envoy::JNI::JniHelper::getThreadLocalEnv()); jclass java_android_network_library_class = - jni_helper.findClass("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); - jmethodID java_clear_test_root_certificates_method_id = jni_helper.getStaticMethodId( + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/utilities/AndroidNetworkLibrary"); + jmethodID java_clear_test_root_certificates_method_id = jni_helper.getStaticMethodIdFromCache( java_android_network_library_class, "clearTestRootCertificates", "()V"); jni_helper.callStaticVoidMethod(java_android_network_library_class, java_clear_test_root_certificates_method_id); diff --git a/mobile/library/jni/jni_utility.cc b/mobile/library/jni/jni_utility.cc index b2308b8ca979..d2f5a5cc01bb 100644 --- a/mobile/library/jni/jni_utility.cc +++ b/mobile/library/jni/jni_utility.cc @@ -11,6 +11,126 @@ namespace Envoy { namespace JNI { +void JniUtility::initCache() { + Envoy::JNI::JniHelper::addToCache("java/lang/Object", /* methods= */ {}, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/lang/Integer", + /* methods= */ + { + {"", "(I)V"}, + {"intValue", "()I"}, + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/lang/ClassLoader", /* methods= */ {}, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/nio/ByteBuffer", + /* methods= */ + { + {"array", "()[B"}, + {"isDirect", "()Z"}, + }, + /* static_methods = */ + { + {"wrap", "([B)Ljava/nio/ByteBuffer;"}, + }, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/lang/Throwable", + /* methods= */ + { + {"getMessage", "()Ljava/lang/String;"}, + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/lang/UnsupportedOperationException", + /* methods= */ {}, /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("[B", /* methods= */ {}, /* static_methods = */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "java/util/LinkedHashMap", /* methods= */ + { + {"", "()V"}, + {"put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"}, + {"get", "(Ljava/lang/Object;)Ljava/lang/Object;"}, + }, + /* static_methods = */ {}, /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Map", /* methods= */ + { + {"entrySet", "()Ljava/util/Set;"}, + + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Map$Entry", /* methods= */ + { + {"getKey", "()Ljava/lang/Object;"}, + {"getValue", "()Ljava/lang/Object;"}, + + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Set", /* methods= */ + { + {"iterator", "()Ljava/util/Iterator;"}, + + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Iterator", /* methods= */ + {{"hasNext", "()Z"}, {"next", "()Ljava/lang/Object;"} + + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "java/util/HashMap", /* methods= */ + {{"", "(I)V"}, {"put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"}}, + /* static_methods = */ {}, /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "java/util/List", /* methods= */ {{"size", "()I"}, {"get", "(I)Ljava/lang/Object;"}}, + /* static_methods = */ {}, /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "java/util/ArrayList", /* methods= */ {{"", "()V"}, {"add", "(Ljava/lang/Object;)Z"}}, + /* static_methods = */ {}, /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel", + /* methods= */ + { + {"", "(JJJJ)V"}, + {"getStreamId", "()J"}, + {"getConnectionId", "()J"}, + {"getAttemptCount", "()J"}, + {"getConsumedBytesFromResponse", "()J"}, + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel", + /* methods= */ + { + {"", "(JJJJJJJJJJJZJJJJ)V"}, + {"getStreamStartMs", "()J"}, + {"getDnsStartMs", "()J"}, + {"getDnsEndMs", "()J"}, + {"getConnectStartMs", "()J"}, + {"getConnectEndMs", "()J"}, + {"getSslStartMs", "()J"}, + {"getSslEndMs", "()J"}, + {"getSendingStartMs", "()J"}, + {"getSendingEndMs", "()J"}, + {"getResponseStartMs", "()J"}, + {"getStreamEndMs", "()J"}, + {"getSocketReused", "()Z"}, + {"getSentByteCount", "()J"}, + {"getReceivedByteCount", "()J"}, + {"getResponseFlags", "()J"}, + {"getUpstreamProtocol", "()J"}, + }, + /* static_methods = */ {}, /* fields= */ {}, + /* static_fields= */ {}); +} + void jniDeleteGlobalRef(void* context) { JNIEnv* env = JniHelper::getThreadLocalEnv(); jobject ref = static_cast(context); @@ -22,8 +142,8 @@ void jniDeleteConstGlobalRef(const void* context) { } int javaIntegerToCppInt(JniHelper& jni_helper, jobject boxed_integer) { - jclass jcls_Integer = jni_helper.findClass("java/lang/Integer"); - jmethodID jmid_intValue = jni_helper.getMethodId(jcls_Integer, "intValue", "()I"); + jclass jcls_Integer = jni_helper.findClassFromCache("java/lang/Integer"); + jmethodID jmid_intValue = jni_helper.getMethodIdFromCache(jcls_Integer, "intValue", "()I"); return jni_helper.callIntMethod(boxed_integer, jmid_intValue); } @@ -99,11 +219,11 @@ envoy_data javaByteBufferToEnvoyData(JniHelper& jni_helper, jobject j_data) { jlong data_length = jni_helper.getDirectBufferCapacity(j_data); if (data_length < 0) { - jclass jcls_ByteBuffer = jni_helper.findClass("java/nio/ByteBuffer"); + jclass jcls_ByteBuffer = jni_helper.findClassFromCache("java/nio/ByteBuffer"); // We skip checking hasArray() because only direct ByteBuffers or array-backed ByteBuffers // are supported. We will crash here if this is an invalid buffer, but guards may be // implemented in the JVM layer. - jmethodID jmid_array = jni_helper.getMethodId(jcls_ByteBuffer, "array", "()[B"); + jmethodID jmid_array = jni_helper.getMethodIdFromCache(jcls_ByteBuffer, "array", "()[B"); LocalRefUniquePtr array = jni_helper.callObjectMethod(j_data, jmid_array); envoy_data native_data = javaByteArrayToEnvoyData(jni_helper, array.get()); @@ -118,11 +238,11 @@ envoy_data javaByteBufferToEnvoyData(JniHelper& jni_helper, jobject j_data, jlon uint8_t* direct_address = jni_helper.getDirectBufferAddress(j_data); if (direct_address == nullptr) { - jclass jcls_ByteBuffer = jni_helper.findClass("java/nio/ByteBuffer"); + jclass jcls_ByteBuffer = jni_helper.findClassFromCache("java/nio/ByteBuffer"); // We skip checking hasArray() because only direct ByteBuffers or array-backed ByteBuffers // are supported. We will crash here if this is an invalid buffer, but guards may be // implemented in the JVM layer. - jmethodID jmid_array = jni_helper.getMethodId(jcls_ByteBuffer, "array", "()[B"); + jmethodID jmid_array = jni_helper.getMethodIdFromCache(jcls_ByteBuffer, "array", "()[B"); LocalRefUniquePtr array = jni_helper.callObjectMethod(j_data, jmid_array); envoy_data native_data = javaByteArrayToEnvoyData(jni_helper, array.get(), data_length); @@ -208,7 +328,7 @@ envoy_map javaArrayOfObjectArrayToEnvoyMap(JniHelper& jni_helper, jobjectArray e LocalRefUniquePtr envoyHeadersToJavaArrayOfObjectArray(JniHelper& jni_helper, const Envoy::Types::ManagedEnvoyHeaders& map) { - jclass jcls_byte_array = jni_helper.findClass("java/lang/Object"); + jclass jcls_byte_array = jni_helper.findClassFromCache("java/lang/Object"); LocalRefUniquePtr javaArray = jni_helper.newObjectArray(2 * map.get().length, jcls_byte_array, nullptr); @@ -227,7 +347,7 @@ envoyHeadersToJavaArrayOfObjectArray(JniHelper& jni_helper, LocalRefUniquePtr vectorStringToJavaArrayOfByteArray(JniHelper& jni_helper, const std::vector& v) { - jclass jcls_byte_array = jni_helper.findClass("[B"); + jclass jcls_byte_array = jni_helper.findClassFromCache("[B"); LocalRefUniquePtr joa = jni_helper.newObjectArray(v.size(), jcls_byte_array, nullptr); @@ -339,28 +459,28 @@ absl::flat_hash_map javaMapToCppMap(JniHelper& jni_hel jobject java_map) { absl::flat_hash_map cpp_map; - auto java_map_class = jni_helper.getObjectClass(java_map); + auto java_map_class = jni_helper.findClassFromCache("java/util/Map"); auto java_entry_set_method_id = - jni_helper.getMethodId(java_map_class.get(), "entrySet", "()Ljava/util/Set;"); + jni_helper.getMethodIdFromCache(java_map_class, "entrySet", "()Ljava/util/Set;"); auto java_entry_set_object = jni_helper.callObjectMethod(java_map, java_entry_set_method_id); - auto java_set_class = jni_helper.getObjectClass(java_entry_set_object.get()); - jclass java_map_entry_class = jni_helper.findClass("java/util/Map$Entry"); + auto java_set_class = jni_helper.findClassFromCache("java/util/Set"); + jclass java_map_entry_class = jni_helper.findClassFromCache("java/util/Map$Entry"); auto java_iterator_method_id = - jni_helper.getMethodId(java_set_class.get(), "iterator", "()Ljava/util/Iterator;"); + jni_helper.getMethodIdFromCache(java_set_class, "iterator", "()Ljava/util/Iterator;"); auto java_get_key_method_id = - jni_helper.getMethodId(java_map_entry_class, "getKey", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_map_entry_class, "getKey", "()Ljava/lang/Object;"); auto java_get_value_method_id = - jni_helper.getMethodId(java_map_entry_class, "getValue", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_map_entry_class, "getValue", "()Ljava/lang/Object;"); auto java_iterator_object = jni_helper.callObjectMethod(java_entry_set_object.get(), java_iterator_method_id); - auto java_iterator_class = jni_helper.getObjectClass(java_iterator_object.get()); + auto java_iterator_class = jni_helper.findClassFromCache("java/util/Iterator"); auto java_has_next_method_id = - jni_helper.getMethodId(java_iterator_class.get(), "hasNext", "()Z"); + jni_helper.getMethodIdFromCache(java_iterator_class, "hasNext", "()Z"); auto java_next_method_id = - jni_helper.getMethodId(java_iterator_class.get(), "next", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_iterator_class, "next", "()Ljava/lang/Object;"); while (jni_helper.callBooleanMethod(java_iterator_object.get(), java_has_next_method_id)) { auto java_entry_object = @@ -381,18 +501,18 @@ absl::flat_hash_map javaMapToCppMap(JniHelper& jni_hel LocalRefUniquePtr cppHeadersToJavaHeaders(JniHelper& jni_helper, const Http::HeaderMap& cpp_headers) { // Use LinkedHashMap to preserve the insertion order. - jclass java_map_class = jni_helper.findClass("java/util/LinkedHashMap"); - auto java_map_init_method_id = jni_helper.getMethodId(java_map_class, "", "()V"); - auto java_map_put_method_id = jni_helper.getMethodId( + jclass java_map_class = jni_helper.findClassFromCache("java/util/LinkedHashMap"); + auto java_map_init_method_id = jni_helper.getMethodIdFromCache(java_map_class, "", "()V"); + auto java_map_put_method_id = jni_helper.getMethodIdFromCache( java_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - auto java_map_get_method_id = - jni_helper.getMethodId(java_map_class, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); + auto java_map_get_method_id = jni_helper.getMethodIdFromCache( + java_map_class, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); auto java_map_object = jni_helper.newObject(java_map_class, java_map_init_method_id); - jclass java_list_class = jni_helper.findClass("java/util/ArrayList"); - auto java_list_init_method_id = jni_helper.getMethodId(java_list_class, "", "()V"); + jclass java_list_class = jni_helper.findClassFromCache("java/util/ArrayList"); + auto java_list_init_method_id = jni_helper.getMethodIdFromCache(java_list_class, "", "()V"); auto java_list_add_method_id = - jni_helper.getMethodId(java_list_class, "add", "(Ljava/lang/Object;)Z"); + jni_helper.getMethodIdFromCache(java_list_class, "add", "(Ljava/lang/Object;)Z"); cpp_headers.iterate([&](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate { std::string cpp_key = std::string(header.key().getStringView()); @@ -428,33 +548,33 @@ LocalRefUniquePtr cppHeadersToJavaHeaders(JniHelper& jni_helper, void javaHeadersToCppHeaders(JniHelper& jni_helper, jobject java_headers, Http::HeaderMap& cpp_headers) { - auto java_map_class = jni_helper.getObjectClass(java_headers); + auto java_map_class = jni_helper.findClassFromCache("java/util/Map"); auto java_entry_set_method_id = - jni_helper.getMethodId(java_map_class.get(), "entrySet", "()Ljava/util/Set;"); + jni_helper.getMethodIdFromCache(java_map_class, "entrySet", "()Ljava/util/Set;"); auto java_entry_set_object = jni_helper.callObjectMethod(java_headers, java_entry_set_method_id); - auto java_set_class = jni_helper.getObjectClass(java_entry_set_object.get()); - jclass java_map_entry_class = jni_helper.findClass("java/util/Map$Entry"); + auto java_set_class = jni_helper.findClassFromCache("java/util/Set"); + jclass java_map_entry_class = jni_helper.findClassFromCache("java/util/Map$Entry"); auto java_map_iter_method_id = - jni_helper.getMethodId(java_set_class.get(), "iterator", "()Ljava/util/Iterator;"); + jni_helper.getMethodIdFromCache(java_set_class, "iterator", "()Ljava/util/Iterator;"); auto java_map_get_key_method_id = - jni_helper.getMethodId(java_map_entry_class, "getKey", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_map_entry_class, "getKey", "()Ljava/lang/Object;"); auto java_map_get_value_method_id = - jni_helper.getMethodId(java_map_entry_class, "getValue", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_map_entry_class, "getValue", "()Ljava/lang/Object;"); auto java_iter_object = jni_helper.callObjectMethod(java_entry_set_object.get(), java_map_iter_method_id); - auto java_iterator_class = jni_helper.getObjectClass(java_iter_object.get()); + auto java_iterator_class = jni_helper.findClassFromCache("java/util/Iterator"); auto java_iter_has_next_method_id = - jni_helper.getMethodId(java_iterator_class.get(), "hasNext", "()Z"); + jni_helper.getMethodIdFromCache(java_iterator_class, "hasNext", "()Z"); auto java_iter_next_method_id = - jni_helper.getMethodId(java_iterator_class.get(), "next", "()Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_iterator_class, "next", "()Ljava/lang/Object;"); - jclass java_list_class = jni_helper.findClass("java/util/List"); - auto java_list_size_method_id = jni_helper.getMethodId(java_list_class, "size", "()I"); + jclass java_list_class = jni_helper.findClassFromCache("java/util/List"); + auto java_list_size_method_id = jni_helper.getMethodIdFromCache(java_list_class, "size", "()I"); auto java_list_get_method_id = - jni_helper.getMethodId(java_list_class, "get", "(I)Ljava/lang/Object;"); + jni_helper.getMethodIdFromCache(java_list_class, "get", "(I)Ljava/lang/Object;"); while (jni_helper.callBooleanMethod(java_iter_object.get(), java_iter_has_next_method_id)) { auto java_entry_object = @@ -481,9 +601,9 @@ void javaHeadersToCppHeaders(JniHelper& jni_helper, jobject java_headers, } bool isJavaDirectByteBuffer(JniHelper& jni_helper, jobject java_byte_buffer) { - jclass java_byte_buffer_class = jni_helper.findClass("java/nio/ByteBuffer"); + jclass java_byte_buffer_class = jni_helper.findClassFromCache("java/nio/ByteBuffer"); auto java_byte_buffer_is_direct_method_id = - jni_helper.getMethodId(java_byte_buffer_class, "isDirect", "()Z"); + jni_helper.getMethodIdFromCache(java_byte_buffer_class, "isDirect", "()Z"); return jni_helper.callBooleanMethod(java_byte_buffer, java_byte_buffer_is_direct_method_id); } @@ -519,9 +639,9 @@ LocalRefUniquePtr cppBufferInstanceToJavaDirectByteBuffer( Buffer::InstancePtr javaNonDirectByteBufferToCppBufferInstance(JniHelper& jni_helper, jobject java_byte_buffer, jlong length) { - jclass java_byte_buffer_class = jni_helper.findClass("java/nio/ByteBuffer"); + jclass java_byte_buffer_class = jni_helper.findClassFromCache("java/nio/ByteBuffer"); auto java_byte_buffer_array_method_id = - jni_helper.getMethodId(java_byte_buffer_class, "array", "()[B"); + jni_helper.getMethodIdFromCache(java_byte_buffer_class, "array", "()[B"); auto java_byte_array = jni_helper.callObjectMethod(java_byte_buffer, java_byte_buffer_array_method_id); ASSERT(java_byte_array != nullptr, "The ByteBuffer argument is not a non-direct ByteBuffer."); @@ -534,9 +654,9 @@ Buffer::InstancePtr javaNonDirectByteBufferToCppBufferInstance(JniHelper& jni_he LocalRefUniquePtr cppBufferInstanceToJavaNonDirectByteBuffer( JniHelper& jni_helper, const Buffer::Instance& cpp_buffer_instance, uint64_t length) { - jclass java_byte_buffer_class = jni_helper.findClass("java/nio/ByteBuffer"); - auto java_byte_buffer_wrap_method_id = - jni_helper.getStaticMethodId(java_byte_buffer_class, "wrap", "([B)Ljava/nio/ByteBuffer;"); + jclass java_byte_buffer_class = jni_helper.findClassFromCache("java/nio/ByteBuffer"); + auto java_byte_buffer_wrap_method_id = jni_helper.getStaticMethodIdFromCache( + java_byte_buffer_class, "wrap", "([B)Ljava/nio/ByteBuffer;"); auto java_byte_array = jni_helper.newByteArray(static_cast(cpp_buffer_instance.length())); auto java_byte_array_elements = jni_helper.getByteArrayElements(java_byte_array.get(), nullptr); cpp_buffer_instance.copyOut(0, length, static_cast(java_byte_array_elements.get())); @@ -545,9 +665,9 @@ LocalRefUniquePtr cppBufferInstanceToJavaNonDirectByteBuffer( } std::string getJavaExceptionMessage(JniHelper& jni_helper, jthrowable throwable) { - jclass java_throwable_class = jni_helper.findClass("java/lang/Throwable"); + jclass java_throwable_class = jni_helper.findClassFromCache("java/lang/Throwable"); auto java_get_message_method_id = - jni_helper.getMethodId(java_throwable_class, "getMessage", "()Ljava/lang/String;"); + jni_helper.getMethodIdFromCache(java_throwable_class, "getMessage", "()Ljava/lang/String;"); auto java_exception_message = jni_helper.callObjectMethod(throwable, java_get_message_method_id); return javaStringToCppString(jni_helper, java_exception_message.get()); @@ -555,19 +675,20 @@ std::string getJavaExceptionMessage(JniHelper& jni_helper, jthrowable throwable) envoy_stream_intel javaStreamIntelToCppStreamIntel(JniHelper& jni_helper, jobject java_stream_intel) { - auto java_stream_intel_class = jni_helper.getObjectClass(java_stream_intel); + auto java_stream_intel_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel"); jlong java_stream_id = jni_helper.callLongMethod( java_stream_intel, - jni_helper.getMethodId(java_stream_intel_class.get(), "getStreamId", "()J")); + jni_helper.getMethodIdFromCache(java_stream_intel_class, "getStreamId", "()J")); jlong java_connection_id = jni_helper.callLongMethod( java_stream_intel, - jni_helper.getMethodId(java_stream_intel_class.get(), "getConnectionId", "()J")); + jni_helper.getMethodIdFromCache(java_stream_intel_class, "getConnectionId", "()J")); jlong java_attempt_count = jni_helper.callLongMethod( java_stream_intel, - jni_helper.getMethodId(java_stream_intel_class.get(), "getAttemptCount", "()J")); + jni_helper.getMethodIdFromCache(java_stream_intel_class, "getAttemptCount", "()J")); jlong java_consumed_bytes_from_response = jni_helper.callLongMethod( - java_stream_intel, - jni_helper.getMethodId(java_stream_intel_class.get(), "getConsumedBytesFromResponse", "()J")); + java_stream_intel, jni_helper.getMethodIdFromCache(java_stream_intel_class, + "getConsumedBytesFromResponse", "()J")); return { /* stream_id= */ static_cast(java_stream_id), @@ -580,9 +701,9 @@ envoy_stream_intel javaStreamIntelToCppStreamIntel(JniHelper& jni_helper, LocalRefUniquePtr cppStreamIntelToJavaStreamIntel(JniHelper& jni_helper, const envoy_stream_intel& stream_intel) { auto java_stream_intel_class = - jni_helper.findClass("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel"); auto java_stream_intel_init_method_id = - jni_helper.getMethodId(java_stream_intel_class, "", "(JJJJ)V"); + jni_helper.getMethodIdFromCache(java_stream_intel_class, "", "(JJJJ)V"); return jni_helper.newObject(java_stream_intel_class, java_stream_intel_init_method_id, static_cast(stream_intel.stream_id), static_cast(stream_intel.connection_id), @@ -592,55 +713,56 @@ LocalRefUniquePtr cppStreamIntelToJavaStreamIntel(JniHelper& jni_helper envoy_final_stream_intel javaFinalStreamIntelToCppFinalStreamIntel(JniHelper& jni_helper, jobject java_final_stream_intel) { - auto java_final_stream_intel_class = jni_helper.getObjectClass(java_final_stream_intel); + auto java_final_stream_intel_class = + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel"); jlong java_stream_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getStreamStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getStreamStartMs", "()J")); jlong java_dns_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getDnsStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getDnsStartMs", "()J")); jlong java_dns_end_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getDnsEndMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getDnsEndMs", "()J")); jlong java_connect_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getConnectStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getConnectStartMs", "()J")); jlong java_connect_end_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getConnectEndMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getConnectEndMs", "()J")); jlong java_ssl_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSslStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSslStartMs", "()J")); jlong java_ssl_end_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSslEndMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSslEndMs", "()J")); jlong java_sending_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSendingStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSendingStartMs", "()J")); jlong java_sending_end_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSendingEndMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSendingEndMs", "()J")); jlong java_response_start_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getResponseStartMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getResponseStartMs", "()J")); jlong java_stream_end_ms = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getStreamEndMs", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getStreamEndMs", "()J")); jboolean java_socket_reused = jni_helper.callBooleanMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSocketReused", "()Z")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSocketReused", "()Z")); jlong java_sent_byte_count = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getSentByteCount", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getSentByteCount", "()J")); jlong java_received_byte_count = jni_helper.callLongMethod( - java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getReceivedByteCount", "()J")); + java_final_stream_intel, jni_helper.getMethodIdFromCache(java_final_stream_intel_class, + "getReceivedByteCount", "()J")); jlong java_response_flags = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getResponseFlags", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getResponseFlags", "()J")); jlong java_upstream_protocol = jni_helper.callLongMethod( java_final_stream_intel, - jni_helper.getMethodId(java_final_stream_intel_class.get(), "getUpstreamProtocol", "()J")); + jni_helper.getMethodIdFromCache(java_final_stream_intel_class, "getUpstreamProtocol", "()J")); return { /* stream_start_ms= */ static_cast(java_stream_start_ms), @@ -666,9 +788,9 @@ LocalRefUniquePtr cppFinalStreamIntelToJavaFinalStreamIntel(JniHelper& jni_helper, const envoy_final_stream_intel& final_stream_intel) { auto java_final_stream_intel_class = - jni_helper.findClass("io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel"); - auto java_final_stream_intel_init_method_id = - jni_helper.getMethodId(java_final_stream_intel_class, "", "(JJJJJJJJJJJZJJJJ)V"); + jni_helper.findClassFromCache("io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel"); + auto java_final_stream_intel_init_method_id = jni_helper.getMethodIdFromCache( + java_final_stream_intel_class, "", "(JJJJJJJJJJJZJJJJ)V"); return jni_helper.newObject(java_final_stream_intel_class, java_final_stream_intel_init_method_id, static_cast(final_stream_intel.stream_start_ms), static_cast(final_stream_intel.dns_start_ms), diff --git a/mobile/library/jni/jni_utility.h b/mobile/library/jni/jni_utility.h index 0ca38f400899..caef665927dc 100644 --- a/mobile/library/jni/jni_utility.h +++ b/mobile/library/jni/jni_utility.h @@ -16,6 +16,11 @@ namespace Envoy { namespace JNI { +struct JniUtility { + /** Initializes the caches for the `JniUtility`. */ + static void initCache(); +}; + void jniDeleteGlobalRef(void* context); void jniDeleteConstGlobalRef(const void* context); @@ -109,9 +114,9 @@ LocalRefUniquePtr cppStringToJavaString(JniHelper& jni_helper, /** Converts from C++'s map-type to Java `HashMap`. */ template LocalRefUniquePtr cppMapToJavaMap(JniHelper& jni_helper, const MapType& cpp_map) { - jclass java_map_class = jni_helper.findClass("java/util/HashMap"); - auto java_map_init_method_id = jni_helper.getMethodId(java_map_class, "", "(I)V"); - auto java_map_put_method_id = jni_helper.getMethodId( + jclass java_map_class = jni_helper.findClassFromCache("java/util/HashMap"); + auto java_map_init_method_id = jni_helper.getMethodIdFromCache(java_map_class, "", "(I)V"); + auto java_map_put_method_id = jni_helper.getMethodIdFromCache( java_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); auto java_map_object = jni_helper.newObject(java_map_class, java_map_init_method_id, cpp_map.size()); diff --git a/mobile/test/common/integration/test_server.cc b/mobile/test/common/integration/test_server.cc index c8727516a5eb..3f69bfe33a1c 100644 --- a/mobile/test/common/integration/test_server.cc +++ b/mobile/test/common/integration/test_server.cc @@ -29,7 +29,7 @@ namespace Envoy { namespace { -std::unique_ptr baseProxyConfig(bool http) { +std::unique_ptr baseProxyConfig(bool http, int port) { std::unique_ptr bootstrap = std::make_unique(); @@ -40,7 +40,7 @@ std::unique_ptr baseProxyConfig(bool ht auto* base_address = listener->mutable_address(); base_address->mutable_socket_address()->set_protocol(envoy::config::core::v3::SocketAddress::TCP); base_address->mutable_socket_address()->set_address("127.0.0.1"); - base_address->mutable_socket_address()->set_port_value(0); + base_address->mutable_socket_address()->set_port_value(port); envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager hcm; hcm.set_stat_prefix("remote hcm"); @@ -137,7 +137,8 @@ TestServer::TestServer() Envoy::ExtensionRegistry::registerFactories(); } -void TestServer::start(TestServerType type) { +void TestServer::start(TestServerType type, int port) { + port_ = port; ASSERT(!upstream_); // pre-setup: see https://github.com/envoyproxy/envoy/blob/main/test/test_runner.cc Logger::Context logging_state(spdlog::level::level_enum::err, @@ -180,7 +181,7 @@ void TestServer::start(TestServerType type) { test_server_ = IntegrationTestServer::create( "", Network::Address::IpVersion::v4, nullptr, nullptr, {}, time_system_, *api_, false, absl::nullopt, Server::FieldValidationConfig(), 1, std::chrono::seconds(1), - Server::DrainStrategy::Gradual, nullptr, false, false, baseProxyConfig(true)); + Server::DrainStrategy::Gradual, nullptr, false, false, baseProxyConfig(true, port_)); test_server_->waitUntilListenersReady(); ENVOY_LOG_MISC(debug, "Http proxy is now running"); return; @@ -195,15 +196,29 @@ void TestServer::start(TestServerType type) { test_server_ = IntegrationTestServer::create( "", Network::Address::IpVersion::v4, nullptr, nullptr, {}, time_system_, *api_, false, absl::nullopt, Server::FieldValidationConfig(), 1, std::chrono::seconds(1), - Server::DrainStrategy::Gradual, nullptr, false, false, baseProxyConfig(false)); + Server::DrainStrategy::Gradual, nullptr, false, false, baseProxyConfig(false, port_)); test_server_->waitUntilListenersReady(); ENVOY_LOG_MISC(debug, "Https proxy is now running"); return; } } - upstream_ = std::make_unique(std::move(factory), port_, version_, - upstream_config_, true); +// We have series of Cronvoy tests which don't bind to port 0, and often hit +// port conflicts with other processes using 127.0.0.1. Default non-apple +// builds to 127.0.0.1 (this fails on iOS and probably OSX with Can't assign +// requested address) +#if !defined(__APPLE__) + if (version_ == Network::Address::IpVersion::v4) { +#else + if (false) { +#endif + auto address = Network::Utility::parseInternetAddressNoThrow("127.0.0.3", port_); + upstream_ = + std::make_unique(std::move(factory), address, upstream_config_, true); + } else { + upstream_ = std::make_unique(std::move(factory), port_, version_, + upstream_config_, true); + } // Legacy behavior for cronet tests. if (type == TestServerType::HTTP3) { diff --git a/mobile/test/common/integration/test_server.h b/mobile/test/common/integration/test_server.h index 68f6bbd59484..c4156aa667b8 100644 --- a/mobile/test/common/integration/test_server.h +++ b/mobile/test/common/integration/test_server.h @@ -31,7 +31,7 @@ class TestServer : public ListenerHooks { /** * Starts the test server. This function blocks until the test server is ready to accept requests. */ - void start(TestServerType type); + void start(TestServerType type, int port = 0); /** * Shutdowns the server server. This function blocks until all the resources have been freed. diff --git a/mobile/test/common/integration/test_server_interface.cc b/mobile/test/common/integration/test_server_interface.cc index e30ba593babd..91dc5f46e74f 100644 --- a/mobile/test/common/integration/test_server_interface.cc +++ b/mobile/test/common/integration/test_server_interface.cc @@ -12,7 +12,7 @@ void start_server(Envoy::TestServerType test_server_type) { weak_test_server_ = strong_test_server_; if (auto server = test_server()) { - server->start(test_server_type); + server->start(test_server_type, 0); } } diff --git a/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory.java b/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory.java index 7e1599f06203..ee4e7f84d5a5 100644 --- a/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory.java +++ b/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory.java @@ -53,8 +53,8 @@ private HttpTestServer(long handle, String ipAddress, int port, String address) * @param trailers the response headers * @return the `HttpTestServer` instance */ - public static native HttpTestServer start(int type, Map headers, String body, - Map trailers); + public static native HttpTestServer start(int type, int port, Map headers, + String body, Map trailers); /** * A convenience method to start the server with an empty response headers, body, and trailers. @@ -64,6 +64,6 @@ public static native HttpTestServer start(int type, Map headers, * @return the `HttpTestServer` instance */ public static HttpTestServer start(int type) { - return start(type, Collections.emptyMap(), "", Collections.emptyMap()); + return start(type, 0, Collections.emptyMap(), "", Collections.emptyMap()); } } diff --git a/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/QuicTestServerTest.java b/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/QuicTestServerTest.java index 654fd86e3d94..67d92c274089 100644 --- a/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/QuicTestServerTest.java +++ b/mobile/test/java/io/envoyproxy/envoymobile/engine/testing/QuicTestServerTest.java @@ -41,7 +41,7 @@ public void setUpEngine() throws Exception { Map headers = new HashMap<>(); headers.put("Cache-Control", "max-age=0"); headers.put("Content-Type", "text/plain"); - httpTestServer = HttpTestServerFactory.start(HttpTestServerFactory.Type.HTTP3, headers, + httpTestServer = HttpTestServerFactory.start(HttpTestServerFactory.Type.HTTP3, 0, headers, "This is a simple text file served by QUIC.\n", Collections.emptyMap()); diff --git a/mobile/test/java/io/envoyproxy/envoymobile/jni/JniHelperTest.java b/mobile/test/java/io/envoyproxy/envoymobile/jni/JniHelperTest.java index 08b6a5f823cd..6f6ad4c2f96e 100644 --- a/mobile/test/java/io/envoyproxy/envoymobile/jni/JniHelperTest.java +++ b/mobile/test/java/io/envoyproxy/envoymobile/jni/JniHelperTest.java @@ -18,7 +18,11 @@ public class JniHelperTest { // Native methods for testing. //================================================================================ public static native void getFieldId(Class clazz, String name, String signature); + public static native void getFieldIdFromCache(String className, String fieldName, + String signature); public static native void getStaticFieldId(Class clazz, String name, String signature); + public static native void getStaticFieldIdFromCache(String className, String fieldName, + String signature); public static native byte getByteField(Class clazz, Object instance, String name, String signature); public static native char getCharField(Class clazz, Object instance, String name, @@ -38,8 +42,12 @@ public static native boolean getBooleanField(Class clazz, Object instance, St public static native Object getObjectField(Class clazz, Object instance, String name, String signature); public static native void getMethodId(Class clazz, String name, String signature); + public static native void getMethodIdFromCache(String className, String methodName, + String signature); public static native void getStaticMethodId(Class clazz, String name, String signature); - public static native Class findClass(String className); + public static native void getStaticMethodIdFromCache(String className, String methodName, + String signature); + public static native Class findClassFromCache(String className); public static native Class getObjectClass(Object object); public static native Object newObject(Class clazz, String name, String signature); public static native void throwNew(String className, String message); @@ -160,21 +168,33 @@ public static void staticVoidMethod() {} static class Foo { private final int field = 1; private static int staticField = 2; + private static void staticMethod() {} } @Test public void testGetFieldId() { + getFieldId(Foo.class, "field", "I"); + } + + @Test + public void testGetFieldIdFromCache() { // Do it in a loop to test the cache. for (int i = 0; i < 10; i++) { - getFieldId(Foo.class, "field", "I"); + getFieldIdFromCache("io/envoyproxy/envoymobile/jni/JniHelperTest$Foo", "field", "I"); } } @Test public void testGetStaticFieldId() { + getStaticFieldId(Foo.class, "staticField", "I"); + } + + @Test + public void testGetStaticFieldIdFromCache() { // Do it in a loop to test the cache. for (int i = 0; i < 10; i++) { - getStaticFieldId(Foo.class, "staticField", "I"); + getStaticFieldIdFromCache("io/envoyproxy/envoymobile/jni/JniHelperTest$Foo", "staticField", + "I"); } } @@ -226,25 +246,36 @@ public void testGetObjectField() { @Test public void testGetMethodId() { + getMethodId(Foo.class, "", "()V"); + } + + @Test + public void testGetMethodIdFromCache() { // Do it in a loop to test the cache. for (int i = 0; i < 10; i++) { - getMethodId(Foo.class, "", "()V"); + getMethodIdFromCache("io/envoyproxy/envoymobile/jni/JniHelperTest$Foo", "", "()V"); } } @Test public void testGetStaticMethodId() { + getStaticMethodId(Foo.class, "staticMethod", "()V"); + } + + @Test + public void testGetStaticMethodIdFromCache() { // Do it in a loop to test the cache. for (int i = 0; i < 10; i++) { - getStaticMethodId(JniHelperTest.class, "staticVoidMethod", "()V"); + getStaticMethodIdFromCache("io/envoyproxy/envoymobile/jni/JniHelperTest$Foo", "staticMethod", + "()V"); } } @Test - public void testFindClass() { + public void testFindClassFromCache() { // Do it in a loop to test the cache. for (int i = 0; i < 10; i++) { - assertThat(findClass("java/lang/Exception")).isEqualTo(Exception.class); + assertThat(findClassFromCache("java/lang/Exception")).isEqualTo(Exception.class); } } diff --git a/mobile/test/java/org/chromium/net/BUILD b/mobile/test/java/org/chromium/net/BUILD index 19773583241e..aefe1cb0152d 100644 --- a/mobile/test/java/org/chromium/net/BUILD +++ b/mobile/test/java/org/chromium/net/BUILD @@ -221,6 +221,33 @@ envoy_mobile_android_test( ], ) +envoy_mobile_android_test( + name = "cronet_http3_test", + srcs = [ + "CronetHttp3Test.java", + ], + native_deps = [ + "//test/jni:libenvoy_jni_with_test_extensions.so", + ] + select({ + "@platforms//os:macos": [ + "//test/jni:libenvoy_jni_with_test_extensions_jnilib", + ], + "//conditions:default": [], + }), + native_lib_name = "envoy_jni_with_test_extensions", + test_class = "org.chromium.net.CronetHttp3Test", + deps = [ + "//library/java/io/envoyproxy/envoymobile/engine:envoy_base_engine_lib", + "//library/java/io/envoyproxy/envoymobile/engine:envoy_engine_lib", + "//library/java/org/chromium/net", + "//library/java/org/chromium/net/impl:cronvoy", + "//library/kotlin/io/envoyproxy/envoymobile:envoy_interfaces_lib", + "//library/kotlin/io/envoyproxy/envoymobile:envoy_lib", + "//test/java/io/envoyproxy/envoymobile/engine/testing:http_test_server_factory_lib", + "//test/java/org/chromium/net/testing", + ], +) + envoy_mobile_android_test( name = "cronet_url_request_context_test", srcs = [ diff --git a/mobile/test/java/org/chromium/net/CronetHttp3Test.java b/mobile/test/java/org/chromium/net/CronetHttp3Test.java new file mode 100644 index 000000000000..41ad3f848fdc --- /dev/null +++ b/mobile/test/java/org/chromium/net/CronetHttp3Test.java @@ -0,0 +1,299 @@ +package org.chromium.net; + +import static org.chromium.net.testing.CronetTestRule.getContext; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import io.envoyproxy.envoymobile.engine.types.EnvoyNetworkType; +import org.chromium.net.impl.CronvoyUrlRequestContext; +import io.envoyproxy.envoymobile.engine.EnvoyEngine; +import org.chromium.net.impl.CronvoyLogger; +import androidx.test.core.app.ApplicationProvider; +import org.chromium.net.testing.TestUploadDataProvider; +import androidx.test.filters.SmallTest; +import org.chromium.net.impl.CronvoyUrlRequestContext; +import org.chromium.net.impl.NativeCronvoyEngineBuilderImpl; +import org.chromium.net.testing.CronetTestRule; +import org.chromium.net.testing.CronetTestRule.CronetTestFramework; +import org.chromium.net.testing.CronetTestRule.RequiresMinApi; +import org.chromium.net.testing.Feature; +import org.chromium.net.testing.TestUrlRequestCallback; +import org.chromium.net.testing.TestUrlRequestCallback.ResponseStep; +import io.envoyproxy.envoymobile.engine.JniLibrary; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import io.envoyproxy.envoymobile.engine.testing.HttpTestServerFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; +/** + * Test CronetEngine with production HTTP/3 logic + */ +@RunWith(RobolectricTestRunner.class) +public class CronetHttp3Test { + @Rule public final CronetTestRule mTestRule = new CronetTestRule(); + + private static final String TAG = CronetHttp3Test.class.getSimpleName(); + + // URLs used for tests. + + // If true, dump envoy logs on test completion. + // Ideally we could override this from the command line but that's TBD. + private boolean printEnvoyLogs = false; + // The HTTP/2 server, set up to alt-svc to the HTTP/3 server + private HttpTestServerFactory.HttpTestServer http2TestServer; + // The HTTP/3 server + private HttpTestServerFactory.HttpTestServer http3TestServer; + // An optional CronvoyLogger, set up if printEnvoyLogs is true. + private CronvoyLogger logger; + // The engine for this test. + private CronvoyUrlRequestContext cronvoyEngine; + // A URL which will point to the IP and port of the test servers. + private String testServerUrl; + + @BeforeClass + public static void loadJniLibrary() { + JniLibrary.loadTestLibrary(); + } + + public void setUp(boolean setUpLogging) throws Exception { + // Set up the HTTP/3 server + Map headers = new HashMap<>(); + http3TestServer = HttpTestServerFactory.start(HttpTestServerFactory.Type.HTTP3, 0, headers, + "This is a simple text file served by QUIC.\n", + Collections.emptyMap()); + // Next set up the HTTP/2 server, advertising HTTP/3 support for the HTTP/3 server + String altSvc = "h3=\":" + http3TestServer.getPort() + "\"; ma=86400"; + headers.put("alt-svc", altSvc); + // Note that the HTTP/2 server must start on the same port as Envoy currently does not accept + // alt-svc with differing ports. This may cause problems if this UDP port is in use at which + // point listening on 127.0.0.N where N!=1 may improve flakiness. + http2TestServer = HttpTestServerFactory.start( + HttpTestServerFactory.Type.HTTP2_WITH_TLS, http3TestServer.getPort(), headers, + "This is a simple text file served by QUIC.\n", Collections.emptyMap()); + testServerUrl = "https://" + http2TestServer.getAddress() + "/"; + + // Optionally, set up logging. This will slow down the tests a bit but make debugging much + // easier. + if (setUpLogging) { + logger = new CronvoyLogger() { + @Override + public void log(int logLevel, String message) { + System.out.print(message); + } + }; + } + + // Set up the Envoy engine. + NativeCronvoyEngineBuilderImpl nativeCronetEngineBuilder = + new NativeCronvoyEngineBuilderImpl(ApplicationProvider.getApplicationContext()); + nativeCronetEngineBuilder.addRuntimeGuard("reset_brokenness_on_nework_change", true); + if (setUpLogging) { + nativeCronetEngineBuilder.setLogger(logger); + nativeCronetEngineBuilder.setLogLevel(EnvoyEngine.LogLevel.TRACE); + } + // Make sure the handshake will work despite lack of real certs. + nativeCronetEngineBuilder.setMockCertVerifierForTesting(); + cronvoyEngine = new CronvoyUrlRequestContext(nativeCronetEngineBuilder); + } + + @After + public void tearDown() throws Exception { + // Shut down Envoy and the test servers. + cronvoyEngine.shutdown(); + http2TestServer.shutdown(); + if (http3TestServer != null) { + http3TestServer.shutdown(); + } + } + + private TestUrlRequestCallback doBasicGetRequest() { + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + UrlRequest.Builder urlRequestBuilder = + cronvoyEngine.newUrlRequestBuilder(testServerUrl, callback, callback.getExecutor()); + urlRequestBuilder.build().start(); + callback.blockForDone(); + return callback; + } + + // Sets up a basic POST request with 4 byte body, set idempotent. + private TestUrlRequestCallback doBasicPostRequest() { + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + ExperimentalUrlRequest.Builder urlRequestBuilder = + cronvoyEngine.newUrlRequestBuilder(testServerUrl, callback, callback.getExecutor()); + urlRequestBuilder.addHeader("content-type", "text"); + urlRequestBuilder.setHttpMethod("POST"); + urlRequestBuilder.setIdempotency(ExperimentalUrlRequest.Builder.IDEMPOTENT); + TestUploadDataProvider dataProvider = new TestUploadDataProvider( + TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()); + dataProvider.addRead("test".getBytes()); + urlRequestBuilder.setUploadDataProvider(dataProvider, callback.getExecutor()); + urlRequestBuilder.build().start(); + callback.blockForDone(); + return callback; + } + + void doInitialHttp2Request() { + // Do a request to https://127.0.0.1:test_server_port/ + TestUrlRequestCallback callback = doBasicGetRequest(); + + // Make sure the request succeeded. It should go out over HTTP/2 as it's the first + // request and HTTP/3 support is not established. + assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); + assertEquals("h2", callback.mResponseInfo.getNegotiatedProtocol()); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + public void basicHttp3Get() throws Exception { + // Ideally we could override this from the command line but that's TBD. + setUp(printEnvoyLogs); + + // Do the initial HTTP/2 request to get the alt-svc response. + doInitialHttp2Request(); + + // Set up a second request, which will hopefully go out over HTTP/3 due to alt-svc + // advertisement. + TestUrlRequestCallback callback = doBasicGetRequest(); + + // Verify the second request used HTTP/3 + assertEquals(200, callback.mResponseInfo.getHttpStatusCode()); + assertEquals("h3", callback.mResponseInfo.getNegotiatedProtocol()); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + public void failToHttp2() throws Exception { + // Ideally we could override this from the command line but that's TBD. + setUp(printEnvoyLogs); + + // Do the initial HTTP/2 request to get the alt-svc response. + doInitialHttp2Request(); + + // Set up a second request, which will hopefully go out over HTTP/3 due to alt-svc + // advertisement. + TestUrlRequestCallback getCallback = doBasicGetRequest(); + + // Verify the second request used HTTP/3 + assertEquals(200, getCallback.mResponseInfo.getHttpStatusCode()); + assertEquals("h3", getCallback.mResponseInfo.getNegotiatedProtocol()); + + // Now stop the HTTP/3 server. + http3TestServer.shutdown(); + http3TestServer = null; + + // The next request will fail on HTTP2 but should succeed on HTTP/2 despite having a body. + TestUrlRequestCallback postCallback = doBasicPostRequest(); + assertEquals(200, postCallback.mResponseInfo.getHttpStatusCode()); + assertEquals("h2", postCallback.mResponseInfo.getNegotiatedProtocol()); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + public void testNoRetryPostAfterHandshake() throws Exception { + setUp(printEnvoyLogs); + + // Do the initial HTTP/2 request to get the alt-svc response. + doInitialHttp2Request(); + + // Set up a second request, which will hopefully go out over HTTP/3 due to alt-svc + // advertisement. + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + UrlRequest.Builder urlRequestBuilder = + cronvoyEngine.newUrlRequestBuilder(testServerUrl, callback, callback.getExecutor()); + // Set the upstream to reset after the request. + urlRequestBuilder.addHeader("reset_after_request", "yes"); + urlRequestBuilder.addHeader("content-type", "text"); + urlRequestBuilder.setHttpMethod("POST"); + TestUploadDataProvider dataProvider = new TestUploadDataProvider( + TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()); + dataProvider.addRead("test".getBytes()); + urlRequestBuilder.setUploadDataProvider(dataProvider, callback.getExecutor()); + + urlRequestBuilder.build().start(); + callback.blockForDone(); + + // Both HTTP/3 and HTTP/2 servers will reset after the request. + assertTrue(callback.mOnErrorCalled); + // There are 2 requests - the initial HTTP/2 alt-svc request and the HTTP/3 request. + // By default, POST requests will not retry. + String stats = cronvoyEngine.getEnvoyEngine().dumpStats(); + assertTrue(stats.contains("cluster.base.upstream_rq_total: 2")); + } + + // Set up to use HTTP/3, then force HTTP/3 to fail post-handshake. The request should + // be retried on HTTP/2 and HTTP/3 will be marked broken. + public void retryPostHandshake() throws Exception { + // Do the initial HTTP/2 request to get the alt-svc response. + doInitialHttp2Request(); + + // Set up a second request, which will hopefully go out over HTTP/3 due to alt-svc + // advertisement. + TestUrlRequestCallback callback = new TestUrlRequestCallback(); + ExperimentalUrlRequest.Builder urlRequestBuilder = + cronvoyEngine.newUrlRequestBuilder(testServerUrl, callback, callback.getExecutor()); + urlRequestBuilder.addHeader("reset_after_request", "yes"); + urlRequestBuilder.addHeader("content-type", "text"); + urlRequestBuilder.setHttpMethod("POST"); + TestUploadDataProvider dataProvider = new TestUploadDataProvider( + TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()); + dataProvider.addRead("test".getBytes()); + urlRequestBuilder.setUploadDataProvider(dataProvider, callback.getExecutor()); + // Set the request to be idempotent so Envoy knows it's safe to retry post-handshake + urlRequestBuilder.setIdempotency(ExperimentalUrlRequest.Builder.IDEMPOTENT); + + urlRequestBuilder.build().start(); + callback.blockForDone(); + + String stats = cronvoyEngine.getEnvoyEngine().dumpStats(); + + // Both HTTP/3 and HTTP/2 servers will reset after the request. + assertTrue(callback.mOnErrorCalled); + // Unlike testNoRetryPostPostHandshake there will be 3 requests - the initial HTTP/2 alt-svc + // request, the HTTP/3 request, and the HTTP/2 retry. + assertTrue(stats.contains("cluster.base.upstream_rq_total: 3")); + assertTrue(stats.contains("cluster.base.upstream_rq_retry: 1")); + // Because H/3 was disallowed on the final retry and TCP connected, H/3 gets marked as broken. + assertTrue(stats.contains("cluster.base.upstream_http3_broken: 1")); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + public void testRetryPostHandshake() throws Exception { + setUp(printEnvoyLogs); + + retryPostHandshake(); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + public void networkChangeAffectsBrokenness() throws Exception { + setUp(printEnvoyLogs); + + // Set HTTP/3 to be marked as broken. + retryPostHandshake(); + + // From prior calls, there was one HTTP/3 connection established. + String preStats = cronvoyEngine.getEnvoyEngine().dumpStats(); + assertTrue(preStats.contains("cluster.base.upstream_cx_http3_total: 1")); + + // This should change QUIC brokenness to "failed recently". + cronvoyEngine.getEnvoyEngine().setPreferredNetwork(EnvoyNetworkType.WLAN); + + // The next request may go out over HTTP/2 or HTTP/3 (depends on who wins the race) + // but HTTP/3 will be tried. + doBasicGetRequest(); + String postStats = cronvoyEngine.getEnvoyEngine().dumpStats(); + assertTrue(postStats.contains("cluster.base.upstream_cx_http3_total: 2")); + } +} diff --git a/mobile/test/jni/jni_helper_test.cc b/mobile/test/jni/jni_helper_test.cc index b215c95bc677..15d4130781bb 100644 --- a/mobile/test/jni/jni_helper_test.cc +++ b/mobile/test/jni/jni_helper_test.cc @@ -11,8 +11,29 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { Envoy::JNI::JniHelper::initialize(vm); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Exception"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/RuntimeException"); + Envoy::JNI::JniHelper::addToCache("java/lang/Exception", /* methods= */ {}, + /* static_methods= */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/lang/RuntimeException", /* methods= */ {}, + /* static_methods= */ {}, /* fields= */ {}, + /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "io/envoyproxy/envoymobile/jni/JniHelperTest$Foo", /* methods= */ + { + {"", "()V"}, + }, + /* static_methods= */ + { + {"staticMethod", "()V"}, + }, + /* fields= */ + { + {"field", "I"}, + }, + /* static_fields= */ + { + {"staticField", "I"}, + }); return Envoy::JNI::JniHelper::getVersion(); } @@ -28,6 +49,19 @@ extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTe jni_helper.getFieldId(clazz, name_ptr.get(), sig_ptr.get()); } +extern "C" JNIEXPORT void JNICALL +Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getFieldIdFromCache(JNIEnv* env, jclass, + jstring class_name, + jstring field_name, + jstring signature) { + Envoy::JNI::JniHelper jni_helper(env); + Envoy::JNI::StringUtfUniquePtr class_name_ptr = jni_helper.getStringUtfChars(class_name, nullptr); + Envoy::JNI::StringUtfUniquePtr field_name_ptr = jni_helper.getStringUtfChars(field_name, nullptr); + Envoy::JNI::StringUtfUniquePtr sig_ptr = jni_helper.getStringUtfChars(signature, nullptr); + auto clazz = jni_helper.findClassFromCache(class_name_ptr.get()); + jni_helper.getFieldIdFromCache(clazz, field_name_ptr.get(), sig_ptr.get()); +} + extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getStaticFieldId( JNIEnv* env, jclass, jclass clazz, jstring name, jstring signature) { Envoy::JNI::JniHelper jni_helper(env); @@ -36,6 +70,19 @@ extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTe jni_helper.getStaticFieldId(clazz, name_ptr.get(), sig_ptr.get()); } +extern "C" JNIEXPORT void JNICALL +Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getStaticFieldIdFromCache(JNIEnv* env, jclass, + jstring class_name, + jstring field_name, + jstring signature) { + Envoy::JNI::JniHelper jni_helper(env); + Envoy::JNI::StringUtfUniquePtr class_name_ptr = jni_helper.getStringUtfChars(class_name, nullptr); + Envoy::JNI::StringUtfUniquePtr field_name_ptr = jni_helper.getStringUtfChars(field_name, nullptr); + Envoy::JNI::StringUtfUniquePtr sig_ptr = jni_helper.getStringUtfChars(signature, nullptr); + auto clazz = jni_helper.findClassFromCache(class_name_ptr.get()); + jni_helper.getStaticFieldIdFromCache(clazz, field_name_ptr.get(), sig_ptr.get()); +} + #define DEFINE_JNI_GET_FIELD(JAVA_TYPE, JNI_TYPE) \ extern "C" JNIEXPORT JNI_TYPE JNICALL \ Java_io_envoyproxy_envoymobile_jni_JniHelperTest_get##JAVA_TYPE##Field( \ @@ -75,6 +122,20 @@ extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTe jni_helper.getMethodId(clazz, name_ptr.get(), sig_ptr.get()); } +extern "C" JNIEXPORT void JNICALL +Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getMethodIdFromCache(JNIEnv* env, jclass, + jstring class_name, + jstring method_name, + jstring signature) { + Envoy::JNI::JniHelper jni_helper(env); + Envoy::JNI::StringUtfUniquePtr class_name_ptr = jni_helper.getStringUtfChars(class_name, nullptr); + Envoy::JNI::StringUtfUniquePtr method_name_ptr = + jni_helper.getStringUtfChars(method_name, nullptr); + Envoy::JNI::StringUtfUniquePtr sig_ptr = jni_helper.getStringUtfChars(signature, nullptr); + auto clazz = jni_helper.findClassFromCache(class_name_ptr.get()); + jni_helper.getMethodIdFromCache(clazz, method_name_ptr.get(), sig_ptr.get()); +} + extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getStaticMethodId(JNIEnv* env, jclass, jclass clazz, jstring name, @@ -85,11 +146,26 @@ Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getStaticMethodId(JNIEnv* env, jni_helper.getStaticMethodId(clazz, name_ptr.get(), sig_ptr.get()); } -extern "C" JNIEXPORT jclass JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTest_findClass( - JNIEnv* env, jclass, jstring class_name) { +extern "C" JNIEXPORT void JNICALL +Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getStaticMethodIdFromCache(JNIEnv* env, jclass, + jstring class_name, + jstring method_name, + jstring signature) { + Envoy::JNI::JniHelper jni_helper(env); + Envoy::JNI::StringUtfUniquePtr class_name_ptr = jni_helper.getStringUtfChars(class_name, nullptr); + Envoy::JNI::StringUtfUniquePtr method_name_ptr = + jni_helper.getStringUtfChars(method_name, nullptr); + Envoy::JNI::StringUtfUniquePtr sig_ptr = jni_helper.getStringUtfChars(signature, nullptr); + auto clazz = jni_helper.findClassFromCache(class_name_ptr.get()); + jni_helper.getStaticMethodIdFromCache(clazz, method_name_ptr.get(), sig_ptr.get()); +} + +extern "C" JNIEXPORT jclass JNICALL +Java_io_envoyproxy_envoymobile_jni_JniHelperTest_findClassFromCache(JNIEnv* env, jclass, + jstring class_name) { Envoy::JNI::JniHelper jni_helper(env); Envoy::JNI::StringUtfUniquePtr class_name_ptr = jni_helper.getStringUtfChars(class_name, nullptr); - return jni_helper.findClass(class_name_ptr.get()); + return jni_helper.findClassFromCache(class_name_ptr.get()); } extern "C" JNIEXPORT jclass JNICALL Java_io_envoyproxy_envoymobile_jni_JniHelperTest_getObjectClass( diff --git a/mobile/test/jni/jni_http_proxy_test_server_factory.cc b/mobile/test/jni/jni_http_proxy_test_server_factory.cc index 2314d0868397..8167402060ef 100644 --- a/mobile/test/jni/jni_http_proxy_test_server_factory.cc +++ b/mobile/test/jni/jni_http_proxy_test_server_factory.cc @@ -9,9 +9,17 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { Envoy::JNI::JniHelper::initialize(vm); - Envoy::JNI::JniHelper::addClassToCache("java/util/Map$Entry"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/engine/testing/HttpProxyTestServerFactory$HttpProxyTestServer"); + Envoy::JNI::JniHelper::addToCache( + "io/envoyproxy/envoymobile/engine/testing/HttpProxyTestServerFactory$HttpProxyTestServer", + /* methods= */ + { + {"", "(JI)V"}, + }, + /* static_methods= */ {}, /* fields= */ + { + {"handle", "J"}, + }, + /* static_fields= */ {}); return Envoy::JNI::JniHelper::getVersion(); } @@ -22,12 +30,12 @@ Java_io_envoyproxy_envoymobile_engine_testing_HttpProxyTestServerFactory_start(J Envoy::ExtensionRegistry::registerFactories(); Envoy::TestServer* test_server = new Envoy::TestServer(); - test_server->start(static_cast(type)); + test_server->start(static_cast(type), 0); - jclass java_http_proxy_server_factory_class = jni_helper.findClass( + jclass java_http_proxy_server_factory_class = jni_helper.findClassFromCache( "io/envoyproxy/envoymobile/engine/testing/HttpProxyTestServerFactory$HttpProxyTestServer"); auto java_init_method_id = - jni_helper.getMethodId(java_http_proxy_server_factory_class, "", "(JI)V"); + jni_helper.getMethodIdFromCache(java_http_proxy_server_factory_class, "", "(JI)V"); int port = test_server->getPort(); return jni_helper .newObject(java_http_proxy_server_factory_class, java_init_method_id, @@ -39,8 +47,9 @@ extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_engine_testing_HttpProxyTestServerFactory_00024HttpProxyTestServer_shutdown( JNIEnv* env, jobject instance) { Envoy::JNI::JniHelper jni_helper(env); - auto java_class = jni_helper.getObjectClass(instance); - auto java_handle_field_id = jni_helper.getFieldId(java_class.get(), "handle", "J"); + auto java_class = jni_helper.findClassFromCache( + "io/envoyproxy/envoymobile/engine/testing/HttpProxyTestServerFactory$HttpProxyTestServer"); + auto java_handle_field_id = jni_helper.getFieldIdFromCache(java_class, "handle", "J"); jlong java_handle = jni_helper.getLongField(instance, java_handle_field_id); Envoy::TestServer* test_server = reinterpret_cast(java_handle); test_server->shutdown(); diff --git a/mobile/test/jni/jni_http_test_server_factory.cc b/mobile/test/jni/jni_http_test_server_factory.cc index dd6409b038ab..16348bad04b4 100644 --- a/mobile/test/jni/jni_http_test_server_factory.cc +++ b/mobile/test/jni/jni_http_test_server_factory.cc @@ -10,30 +10,69 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { Envoy::JNI::JniHelper::initialize(vm); - Envoy::JNI::JniHelper::addClassToCache("java/util/Map$Entry"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory$HttpTestServer"); + Envoy::JNI::JniHelper::addToCache("java/util/Map", /* methods= */ + { + {"entrySet", "()Ljava/util/Set;"}, + + }, + /* static_methods = */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Map$Entry", /* methods= */ + { + {"getKey", "()Ljava/lang/Object;"}, + {"getValue", "()Ljava/lang/Object;"}, + + }, + /* static_methods = */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Set", /* methods= */ + { + {"iterator", "()Ljava/util/Iterator;"}, + + }, + /* static_methods = */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache("java/util/Iterator", /* methods= */ + { + {"hasNext", "()Z"}, + {"next", "()Ljava/lang/Object;"}, + + }, + /* static_methods = */ {}, + /* fields= */ {}, /* static_fields= */ {}); + Envoy::JNI::JniHelper::addToCache( + "io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory$HttpTestServer", + /* methods= */ + { + {"", "(JLjava/lang/String;ILjava/lang/String;)V"}, + }, + /* static_methods= */ {}, /* fields= */ + { + {"handle", "J"}, + }, + /* static_fields= */ {}); return Envoy::JNI::JniHelper::getVersion(); } extern "C" JNIEXPORT jobject JNICALL Java_io_envoyproxy_envoymobile_engine_testing_HttpTestServerFactory_start( - JNIEnv* env, jclass, jint type, jobject headers, jstring body, jobject trailers) { + JNIEnv* env, jclass, jint type, jint requested_port, jobject headers, jstring body, + jobject trailers) { Envoy::JNI::JniHelper jni_helper(env); Envoy::ExtensionRegistry::registerFactories(); Envoy::TestServer* test_server = new Envoy::TestServer(); - test_server->start(static_cast(type)); + test_server->start(static_cast(type), requested_port); auto cpp_headers = Envoy::JNI::javaMapToCppMap(jni_helper, headers); auto cpp_body = Envoy::JNI::javaStringToCppString(jni_helper, body); auto cpp_trailers = Envoy::JNI::javaMapToCppMap(jni_helper, trailers); test_server->setResponse(cpp_headers, cpp_body, cpp_trailers); - jclass java_http_server_factory_class = jni_helper.findClass( + jclass java_http_server_factory_class = jni_helper.findClassFromCache( "io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory$HttpTestServer"); - auto java_init_method_id = jni_helper.getMethodId(java_http_server_factory_class, "", - "(JLjava/lang/String;ILjava/lang/String;)V"); + auto java_init_method_id = jni_helper.getMethodIdFromCache( + java_http_server_factory_class, "", "(JLjava/lang/String;ILjava/lang/String;)V"); auto ip_address = Envoy::JNI::cppStringToJavaString(jni_helper, test_server->getIpAddress()); int port = test_server->getPort(); auto address = Envoy::JNI::cppStringToJavaString(jni_helper, test_server->getAddress()); @@ -48,8 +87,9 @@ extern "C" JNIEXPORT void JNICALL Java_io_envoyproxy_envoymobile_engine_testing_HttpTestServerFactory_00024HttpTestServer_shutdown( JNIEnv* env, jobject instance) { Envoy::JNI::JniHelper jni_helper(env); - auto java_class = jni_helper.getObjectClass(instance); - auto java_handle_field_id = jni_helper.getFieldId(java_class.get(), "handle", "J"); + auto java_class = jni_helper.findClassFromCache( + "io/envoyproxy/envoymobile/engine/testing/HttpTestServerFactory$HttpTestServer"); + auto java_handle_field_id = jni_helper.getFieldIdFromCache(java_class, "handle", "J"); jlong java_handle = jni_helper.getLongField(instance, java_handle_field_id); Envoy::TestServer* test_server = reinterpret_cast(java_handle); test_server->shutdown(); diff --git a/mobile/test/jni/jni_utility_test.cc b/mobile/test/jni/jni_utility_test.cc index b3903d67e122..9799ddeb3dc9 100644 --- a/mobile/test/jni/jni_utility_test.cc +++ b/mobile/test/jni/jni_utility_test.cc @@ -13,20 +13,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { Envoy::JNI::JniHelper::initialize(vm); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Object"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Integer"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/ClassLoader"); - Envoy::JNI::JniHelper::addClassToCache("java/nio/ByteBuffer"); - Envoy::JNI::JniHelper::addClassToCache("java/lang/Throwable"); - Envoy::JNI::JniHelper::addClassToCache("[B"); - Envoy::JNI::JniHelper::addClassToCache("java/util/Map$Entry"); - Envoy::JNI::JniHelper::addClassToCache("java/util/LinkedHashMap"); - Envoy::JNI::JniHelper::addClassToCache("java/util/HashMap"); - Envoy::JNI::JniHelper::addClassToCache("java/util/List"); - Envoy::JNI::JniHelper::addClassToCache("java/util/ArrayList"); - Envoy::JNI::JniHelper::addClassToCache("io/envoyproxy/envoymobile/engine/types/EnvoyStreamIntel"); - Envoy::JNI::JniHelper::addClassToCache( - "io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel"); + Envoy::JNI::JniUtility::initCache(); return Envoy::JNI::JniHelper::getVersion(); } diff --git a/mobile/test/kotlin/integration/BUILD b/mobile/test/kotlin/integration/BUILD index 4cb12437f196..9472c9806dab 100644 --- a/mobile/test/kotlin/integration/BUILD +++ b/mobile/test/kotlin/integration/BUILD @@ -1,6 +1,5 @@ load("@envoy//bazel:envoy_build_system.bzl", "envoy_mobile_package") load("@envoy_mobile//bazel:envoy_mobile_android_test.bzl", "envoy_mobile_android_test") -load("@io_bazel_rules_kotlin//kotlin:android.bzl", "kt_android_library") licenses(["notice"]) # Apache 2 @@ -372,14 +371,3 @@ envoy_mobile_android_test( "//library/kotlin/io/envoyproxy/envoymobile:envoy_lib", ], ) - -kt_android_library( - name = "test_utilities", - srcs = [ - "TestUtilities.kt", - ], - deps = [ - "//library/kotlin/io/envoyproxy/envoymobile:envoy_interfaces_lib", - "@maven//:junit_junit", - ], -) diff --git a/mobile/test/kotlin/integration/ReceiveDataTest.kt b/mobile/test/kotlin/integration/ReceiveDataTest.kt index bab47e1cc2f6..630c55d1c766 100644 --- a/mobile/test/kotlin/integration/ReceiveDataTest.kt +++ b/mobile/test/kotlin/integration/ReceiveDataTest.kt @@ -31,6 +31,7 @@ class ReceiveDataTest { httpTestServer = HttpTestServerFactory.start( HttpTestServerFactory.Type.HTTP2_WITH_TLS, + 0, mapOf(), "data", mapOf() diff --git a/mobile/test/kotlin/integration/ReceiveTrailersTest.kt b/mobile/test/kotlin/integration/ReceiveTrailersTest.kt index abb176bc905d..6d43cad5c61a 100644 --- a/mobile/test/kotlin/integration/ReceiveTrailersTest.kt +++ b/mobile/test/kotlin/integration/ReceiveTrailersTest.kt @@ -35,6 +35,7 @@ class ReceiveTrailersTest { httpTestServer = HttpTestServerFactory.start( HttpTestServerFactory.Type.HTTP2_WITH_TLS, + 0, mapOf(), "data", mapOf(TRAILER_NAME to TRAILER_VALUE) diff --git a/mobile/test/kotlin/integration/SendDataTest.kt b/mobile/test/kotlin/integration/SendDataTest.kt index 094db7c32a26..05d5c1533bfe 100644 --- a/mobile/test/kotlin/integration/SendDataTest.kt +++ b/mobile/test/kotlin/integration/SendDataTest.kt @@ -36,6 +36,7 @@ class SendDataTest { httpTestServer = HttpTestServerFactory.start( HttpTestServerFactory.Type.HTTP2_WITH_TLS, + 0, mapOf(), "data", mapOf() diff --git a/mobile/test/kotlin/integration/TestUtilities.kt b/mobile/test/kotlin/integration/TestUtilities.kt deleted file mode 100644 index acb78ab2870e..000000000000 --- a/mobile/test/kotlin/integration/TestUtilities.kt +++ /dev/null @@ -1,52 +0,0 @@ -package test.kotlin.integration - -import io.envoyproxy.envoymobile.Engine -import java.time.Instant -import java.util.concurrent.TimeUnit -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import org.junit.Assert.fail - -/** Gets the stats in the form of `Map`. */ -fun Engine.getStats(): Map { - // `dumpStats()` produces the following format: - // key1: value1 - // key2: value2 - // key3: value3 - // ... - val lines = dumpStats().split("\n") - return lines - .mapNotNull { - val keyValue = it.split(": ") - if (keyValue.size == 2) { - Pair(keyValue[0], keyValue[1]) - } else { - null - } - } - .toMap() -} - -/** - * Waits for 5 seconds (default) until the stat of the given [name] is greater than equal the - * specified [expectedValue]. - * - * @throws java.lang.AssertionError throw when the the operation timed out waiting for the stat - * value to be greater than the [expectedValue]. - */ -fun Engine.waitForStatGe( - name: String, - expectedValue: Long, - timeout: Duration = 5.seconds, -) { - val waitTime = Instant.now().plusMillis(timeout.toLong(DurationUnit.MILLISECONDS)) - var currentValue = getStats()[name] - while (currentValue == null || currentValue.toLong() < expectedValue) { - if (Instant.now() > waitTime) { - fail("Timed out waiting for $name to be greater than equal $expectedValue") - } - TimeUnit.MILLISECONDS.sleep(10) - currentValue = getStats()[name] - } -} diff --git a/mobile/test/performance/files_em_does_not_use b/mobile/test/performance/files_em_does_not_use index 5d9be3672ef2..16c1f69644f8 100644 --- a/mobile/test/performance/files_em_does_not_use +++ b/mobile/test/performance/files_em_does_not_use @@ -20,3 +20,4 @@ source/common/tls/ocsp/ocsp.h source/common/formatter/http_specific_formatter.h source/common/formatter/stream_info_formatter.h source/common/tls/default_tls_certificate_selector.h +source/common/json/json_streamer.h diff --git a/source/common/common/BUILD b/source/common/common/BUILD index 2f4558fb3c6c..ec85b28e5ba1 100644 --- a/source/common/common/BUILD +++ b/source/common/common/BUILD @@ -476,6 +476,7 @@ envoy_cc_library( "//envoy/common:interval_set_interface", "//envoy/common:time_interface", "//source/common/singleton:const_singleton", + "@com_googlesource_code_re2//:re2", ], ) diff --git a/source/common/common/utility.cc b/source/common/common/utility.cc index 463683960a20..91dcd9d0f263 100644 --- a/source/common/common/utility.cc +++ b/source/common/common/utility.cc @@ -18,13 +18,13 @@ #include "source/common/common/hash.h" #include "source/common/singleton/const_singleton.h" -#include "absl/container/node_hash_map.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/str_join.h" #include "absl/strings/str_replace.h" #include "absl/strings/str_split.h" #include "absl/time/time.h" +#include "re2/re2.h" #include "spdlog/spdlog.h" namespace Envoy { @@ -33,9 +33,11 @@ namespace { class SpecifierConstantValues { public: - // This captures three groups: subsecond-specifier, subsecond-specifier width and - // second-specifier. - const std::regex PATTERN{"(%([1-9])?f)|(%s)", std::regex::optimize}; + // This pattern contains three parts: + // 1. %[1-9*]?f: Envoy subseconds specifier with an optional width. + // 2. %s: Envoy seconds specifier. + // 3. %E[1-9*][Sf]: absl::FormatTime() seconds/subseconds specifier. + const re2::RE2 RE2_PATTERN{"(%[1-9*]?f|%s|%E[1-9*][Sf])"}; }; using SpecifierConstants = ConstSingleton; @@ -68,160 +70,240 @@ const std::string errorDetails(int error_code) { #endif } -std::string DateFormatter::fromTime(const SystemTime& time) const { - struct CachedTime { - // The string length of a number of seconds since the Epoch. E.g. for "1528270093", the length - // is 10. - size_t seconds_length; - - // A container object to hold a absl::FormatTime string, its timestamp (in seconds) and a list - // of position offsets for each specifier found in a format string. - struct Formatted { - // The resulted string after format string is passed to absl::FormatTime at a given point in - // time. - std::string str; - - // A timestamp (in seconds) when this object is created. - std::chrono::seconds epoch_time_seconds; - - // List of offsets for each specifier found in a format string. This is needed to compensate - // the position of each recorded specifier due to the possible size change of the previous - // segment (after being formatted). - SpecifierOffsets specifier_offsets; - }; - // A map is used to keep different formatted format strings at a given second. - absl::node_hash_map formatted; - }; - static thread_local CachedTime cached_time_utc; - static thread_local CachedTime cached_time_local; +std::string DateFormatter::fromTime(SystemTime time) const { + // A map is used to keep different formatted format strings at a given seconds. + static thread_local CachedTimes CACHE; + static thread_local CachedTimes CACHE_LOCAL; - const std::chrono::nanoseconds epoch_time_ns = - std::chrono::duration_cast(time.time_since_epoch()); + if (specifiers_.empty()) { + return {}; + } - const std::chrono::seconds epoch_time_seconds = - std::chrono::duration_cast(epoch_time_ns); + CachedTimes& cached_times = local_time_ ? CACHE_LOCAL : CACHE; + + const auto epoch_time_ss = + std::chrono::duration_cast(time.time_since_epoch()); + + const auto iter = cached_times.find(raw_format_string_, raw_format_hash_); + + if (iter == cached_times.end() || iter->second.epoch_time_seconds != epoch_time_ss) { + // No cached entry found for the given format string and time. - CachedTime& cached_time = local_time_ ? cached_time_local : cached_time_utc; - const auto& item = cached_time.formatted.find(raw_format_string_); - if (item == cached_time.formatted.end() || - item->second.epoch_time_seconds != epoch_time_seconds) { // Remove all the expired cached items. - for (auto it = cached_time.formatted.cbegin(); it != cached_time.formatted.cend();) { - if (it->second.epoch_time_seconds != epoch_time_seconds) { + for (auto it = cached_times.cbegin(); it != cached_times.cend();) { + if (it->second.epoch_time_seconds != epoch_time_ss) { auto next_it = std::next(it); - cached_time.formatted.erase(it); + cached_times.erase(it); it = next_it; } else { ++it; } } - const time_t current_time = std::chrono::system_clock::to_time_t(time); - - // Build a new formatted format string at current time. - CachedTime::Formatted formatted; - const std::string seconds_str = fmt::format_int(epoch_time_seconds.count()).str(); - formatted.str = - fromTimeAndPrepareSpecifierOffsets(current_time, formatted.specifier_offsets, seconds_str); - cached_time.seconds_length = seconds_str.size(); + auto new_iter = cached_times.emplace( + std::make_pair(raw_format_string_, formatTimeAndOffsets(time, epoch_time_ss))); - // Stamp the formatted string using the current epoch time in seconds, and then cache it in. - formatted.epoch_time_seconds = epoch_time_seconds; - cached_time.formatted.emplace(std::make_pair(raw_format_string_, formatted)); + ASSERT(new_iter.second); + return new_iter.first->second.formatted; } - const auto& formatted = cached_time.formatted.at(raw_format_string_); - ASSERT(specifiers_.size() == formatted.specifier_offsets.size()); + const auto& formatted = iter->second; + ASSERT(specifiers_.size() == formatted.offsets.size()); - // Copy the current cached formatted format string, then replace its subseconds part (when it has - // non-zero width) by correcting its position using prepared subseconds offsets. - std::string formatted_str = formatted.str; - std::string nanoseconds = fmt::format_int(epoch_time_ns.count()).str(); - // Special case handling for beginning of time, we should never need to do this outside of - // tests or a time machine. - if (nanoseconds.size() < 10) { - nanoseconds = std::string(10 - nanoseconds.size(), '0') + nanoseconds; - } - - for (size_t i = 0; i < specifiers_.size(); ++i) { - const auto& specifier = specifiers_.at(i); + // Copy the current cached formatted format string, then replace its subseconds specifier + // (when it has non-zero width) by correcting its position using prepared subseconds offsets. + std::string formatted_str = formatted.formatted; - // When specifier.width_ is zero, skip the replacement. This is the last segment or it has no - // specifier. - if (specifier.width_ > 0 && !specifier.second_) { - ASSERT(specifier.position_ + formatted.specifier_offsets.at(i) < formatted_str.size()); - formatted_str.replace(specifier.position_ + formatted.specifier_offsets.at(i), - specifier.width_, - nanoseconds.substr(cached_time.seconds_length, specifier.width_)); + for (size_t i = specifiers_.size(); i != 0; i--) { + if (specifiers_[i - 1].subsecondsSpecifier()) { + const auto offset = formatted.offsets[i - 1]; + const auto substr = specifiers_[i - 1].subsecondsToString(time); + formatted_str.replace(offset.offset, offset.length, substr); } } - - ASSERT(formatted_str.size() == formatted.str.size()); return formatted_str; } -void DateFormatter::parse(const std::string& format_string) { - std::string suffix = format_string; - std::smatch matched; - // "step" is the last specifier's position + the last specifier's width. It's not the current - // position in "format_string" because the length has changed. It is actually the index which - // points to the end of the last specifier in formatted string (generated in the future). - size_t step = 0; - while (regex_search(suffix, matched, SpecifierConstants::get().PATTERN)) { - // The std::smatch matched for (%([1-9])?f)|(%s): [all, subsecond-specifier, subsecond-specifier - // width, second-specifier]. - const std::string& width_specifier = matched[2]; - const std::string& second_specifier = matched[3]; - - // In the template string to be used in runtime substitution, the width is the number of - // characters to be replaced. - const size_t width = width_specifier.empty() ? 9 : width_specifier.at(0) - '0'; - - ASSERT(!suffix.empty()); - // This records matched position, the width of current subsecond pattern, and also the string - // segment before the matched position. These values will be used later at data path. - specifiers_.emplace_back( - second_specifier.empty() - ? Specifier(step + matched.position(), width, suffix.substr(0, matched.position())) - : Specifier(step + matched.position(), suffix.substr(0, matched.position()))); - step = specifiers_.back().position_ + specifiers_.back().width_; - suffix = matched.suffix(); +void DateFormatter::parse(absl::string_view format_string) { + absl::string_view format = format_string; + absl::string_view matched; + + // PartialMatch will return the leftmost-longest match. And the matched will be mutated + // to point to matched piece + while (re2::RE2::PartialMatch(format, SpecifierConstants::get().RE2_PATTERN, &matched)) { + ASSERT(!matched.empty()); + + // Get matched position based the matched and format view. For example: + // this-is-prefix-string-%s-this-is-suffix-string + // |------ prefix -------|| | + // | matched | + // |------------------ format ------------------| + const size_t prefix_length = matched.data() - format.data(); + + std::string prefix_string = std::string(format.substr(0, prefix_length)); + + Specifier::SpecifierType specifier{}; + uint8_t width{}; + + if (matched.size() == 2) { + // Handle the seconds specifier (%s) or subseconds specifier without width (%f). + + ASSERT(matched[1] == 's' || matched[1] == 'f'); + if (matched[1] == 's') { + specifier = Specifier::SpecifierType::Second; + } else { + specifier = Specifier::SpecifierType::EnvoySubsecond; + width = 9; + } + } else if (matched.size() == 3) { + // Handle subseconds specifier with width (%#f, %*f, '#' means number between 1-9, + // '*' is literal). + + ASSERT(matched[2] == 'f'); + specifier = Specifier::SpecifierType::EnvoySubsecond; + width = matched[1] == '*' ? std::numeric_limits::max() : matched[1] - '0'; + } else { + // To improve performance, we will cache the formatted string for every second. + // And when doing the runtime substitution, we will get the cached result and + // replace the subseconds part. + // In order to make sure the subseconds part of absl::FormatTime() can be replaced, + // we need to handle the subseconds specifier of absl::FormatTime() here. + + // Handle the absl subseconds specifier (%E#S, %E*S, %E#f, %E*f, '#' means number + // between 1-9, '*' is literal). + + ASSERT(matched.size() == 4); + ASSERT(matched[3] == 'S' || matched[3] == 'f'); + + if (matched[3] == 'S') { + // %E#S or %E*S includes the seconds, dot, and subseconds. For example, %E6S + // will output "30.654321". + // We will let the absl::FormatTime() to handle the seconds parts. So we need + // to add the seconds specifier to the prefix string to ensure the final + // formatted string is correct. + prefix_string.push_back('%'); + prefix_string.push_back('S'); + + specifier = Specifier::SpecifierType::AbslSubsecondS; + } else { + specifier = Specifier::SpecifierType::AbslSubsecondF; + } + + width = matched[2] == '*' ? std::numeric_limits::max() : matched[2] - '0'; + } + + if (!prefix_string.empty()) { + specifiers_.push_back(Specifier(prefix_string)); + } + + ASSERT(format.size() >= prefix_length + matched.size()); + ASSERT(specifier != Specifier::SpecifierType::String); + specifiers_.emplace_back(Specifier(specifier, width)); + format = format.substr(prefix_length + matched.size()); } // To capture the segment after the last specifier pattern of a format string by creating a zero // width specifier. E.g. %3f-this-is-the-last-%s-segment-%Y-until-this. - if (!suffix.empty()) { - Specifier specifier(step, 0, suffix); - specifiers_.emplace_back(specifier); + if (!format.empty()) { + specifiers_.emplace_back(Specifier(format)); + } +} + +std::string DateFormatter::Specifier::subsecondsToString(SystemTime time) const { + ASSERT(specifier_ > SpecifierType::Second); + ASSERT(width_ > 0); + + absl::string_view nanoseconds; + + std::string string_buffer; + fmt::format_int formatted(std::chrono::nanoseconds(time.time_since_epoch()).count()); + + // 1. Get the subseconds part of the formatted time. + if (formatted.size() < 9) { + // Special case. This should never happen in actual practice. + string_buffer = std::string(9 - formatted.size(), '0'); + string_buffer.append(formatted.data(), formatted.size()); + nanoseconds = string_buffer; + } else { + nanoseconds = absl::string_view(formatted.data() + formatted.size() - 9, 9); + } + ASSERT(nanoseconds.size() == 9); + + // 2. Calculate the actual width that will be used. + uint8_t width = width_; + if (width == std::numeric_limits::max()) { + // Dynamic width specifier. Remove trailing zeros. + if (const auto i = nanoseconds.find_last_not_of('0'); i != absl::string_view::npos) { + width = i + 1; + } else { + // This only happens for subseconds specifiers with dynamic width (%E*S, %E*f, %*f) + // and the subseconds are all zeros. + width = 0; + } } + + // 3. Handle the specifiers of %E#S and %E*S. The seconds part will be handled by + // absl::FormatTime() by string specifier. So we only need to return the dot and + // subseconds part. + if (specifier_ == SpecifierType::AbslSubsecondS) { + if (width == 0) { + // No subseconds and dot for %E*S in this case. + return {}; + } + + std::string output; + output.push_back('.'); // Add the dot. + output.append(nanoseconds.data(), width); + return output; + } + + // 4. Handle the specifiers of %E#f, %E*f, and %f, %#f, %*f. At least one subsecond digit + // will be returned for these specifiers even if the subseconds are all zeros and dynamic + // width is used. + return std::string(nanoseconds.substr(0, std::max(width, 1))); +} + +std::string DateFormatter::Specifier::toString(SystemTime time, + std::chrono::seconds epoch_time_seconds, + bool local) const { + switch (specifier_) { + case SpecifierType::String: + ASSERT(!string_.empty()); + // Handle the string first. It may be absl::FormatTime() format string. + if (absl_format_) { + return absl::FormatTime(string_, absl::FromChrono(time), + local ? absl::LocalTimeZone() : absl::UTCTimeZone()); + } else { + return string_; + } + case SpecifierType::Second: + // Handle the seconds specifier. + return fmt::format_int(epoch_time_seconds.count()).str(); + case SpecifierType::EnvoySubsecond: + case SpecifierType::AbslSubsecondS: + case SpecifierType::AbslSubsecondF: + // Handle the sub-seconds specifier. + return subsecondsToString(time); + } + + return {}; // Should never reach here. Make the gcc happy. } -std::string -DateFormatter::fromTimeAndPrepareSpecifierOffsets(time_t time, SpecifierOffsets& specifier_offsets, - const absl::string_view seconds_str) const { - std::string formatted_time; +DateFormatter::CacheableTime +DateFormatter::formatTimeAndOffsets(SystemTime time, + std::chrono::seconds epoch_time_seconds) const { + CacheableTime ret; + ret.epoch_time_seconds = epoch_time_seconds; + ret.formatted.reserve(64); + ret.offsets.reserve(specifiers_.size()); - int32_t previous = 0; - specifier_offsets.reserve(specifiers_.size()); for (const auto& specifier : specifiers_) { - std::string current_format = - absl::FormatTime(specifier.segment_, absl::FromTimeT(time), - local_time_ ? absl::LocalTimeZone() : absl::UTCTimeZone()); - absl::StrAppend(&formatted_time, current_format, - specifier.second_ ? seconds_str : std::string(specifier.width_, '?')); - - // This computes and saves offset of each specifier's pattern to correct its position after the - // previous string segment is formatted. An offset can be a negative value. - // - // If the current specifier is a second specifier (%s), it needs to be corrected by 2. - const int32_t offset = - (current_format.length() + (specifier.second_ ? (seconds_str.size() - 2) : 0)) - - specifier.segment_.size(); - specifier_offsets.emplace_back(previous + offset); - previous += offset; - } - - return formatted_time; + const auto offset = ret.formatted.size(); + ret.formatted.append(specifier.toString(time, epoch_time_seconds, local_time_)); + ret.offsets.push_back({offset, ret.formatted.size() - offset}); + } + + return ret; } std::string DateFormatter::now(TimeSource& time_source) const { diff --git a/source/common/common/utility.h b/source/common/common/utility.h index 872904b6a47a..47d1082da1cd 100644 --- a/source/common/common/utility.h +++ b/source/common/common/utility.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/container/node_hash_map.h" #include "absl/strings/string_view.h" namespace Envoy { @@ -44,8 +46,9 @@ const std::string errorDetails(int error_code); */ class DateFormatter { public: - DateFormatter(const std::string& format_string, bool local_time = false) - : raw_format_string_(format_string), local_time_(local_time) { + DateFormatter(absl::string_view format_string, bool local_time = false) + : raw_format_string_(format_string), + raw_format_hash_(CachedTimes::hasher{}(raw_format_string_)), local_time_(local_time) { parse(format_string); } @@ -53,7 +56,7 @@ class DateFormatter { * @return std::string representing the GMT/UTC time based on the input time, * or local zone time when local_time_ is true. */ - std::string fromTime(const SystemTime& time) const; + std::string fromTime(SystemTime time) const; /** * @param time_source time keeping source. @@ -67,48 +70,101 @@ class DateFormatter { const std::string& formatString() const { return raw_format_string_; } private: - void parse(const std::string& format_string); - - using SpecifierOffsets = std::vector; - std::string fromTimeAndPrepareSpecifierOffsets(time_t time, SpecifierOffsets& specifier_offsets, - const absl::string_view seconds_str) const; + void parse(absl::string_view format_string); // A container to hold a specifiers (%f, %Nf, %s) found in a format string. - struct Specifier { - // To build a subsecond-specifier. - Specifier(const size_t position, const size_t width, const std::string& segment) - : position_(position), width_(width), segment_(segment), second_(false) {} + class Specifier { + public: + enum class SpecifierType : uint8_t { + String = 0, // means the specifier is a string specifier. + Second, // means the specifier is a seconds specifier. + EnvoySubsecond, // subseconds specifiers %f, %#f and %*f that supported by Envoy. + AbslSubsecondS, // subseconds specifiers %E#S, %E*S. + AbslSubsecondF, // subseconds specifiers %E#f, %E*f. + }; + + // To build a seconds or subseconds specifier. + Specifier(SpecifierType specifier, uint8_t width) : specifier_(specifier), width_(width) { + // String specifier should call another constructor. + ASSERT(specifier != SpecifierType::String); + + if (specifier == SpecifierType::Second) { + // Seconds specifier. + ASSERT(width == 0); + } else { + ASSERT(width >= 1); + ASSERT(width <= 9 || width == std::numeric_limits::max()); + } + } - // To build a second-specifier (%s), the number of characters to be replaced is always 2. - Specifier(const size_t position, const std::string& segment) - : position_(position), width_(2), segment_(segment), second_(true) {} + // To build a string specifier. + Specifier(absl::string_view string) + : string_(string), absl_format_(string_.find('%') != std::string::npos), + specifier_(SpecifierType::String) { + ASSERT(!string.empty()); + } - // The position/index of a specifier in a format string. - const size_t position_; + // Format a time point based on the specifier. + std::string toString(SystemTime time, std::chrono::seconds epoch_time_seconds, + bool local_time_zone) const; - // The width of a specifier, e.g. given %3f, the width is 3. If %f is set as the - // specifier, the width value should be 9 (the number of nanosecond digits). - const size_t width_; + // Format a time point based on the specifier. This should only be called for subseconds + // specifiers. + std::string subsecondsToString(SystemTime time) const; - // The string before the current specifier's position and after the previous found specifier. A - // segment may include absl::FormatTime accepted specifiers. E.g. given + /** + * @return bool whether the specifier is a subseconds specifier. + */ + bool subsecondsSpecifier() const { return specifier_ > SpecifierType::Second; } + + private: + // The format string before the current specifier's position and after the previous found + // specifier. The string may include absl::FormatTime accepted specifiers. E.g. given // "%3f-this-i%s-a-segment-%4f", the current specifier is "%4f" and the segment is - // "-this-i%s-a-segment-". - const std::string segment_; + // "-a-segment-". + const std::string string_; + // If the string_ contains absl::FormatTime accepted specifiers, this is true. Or string_ + // will be treated as raw string. + const bool absl_format_{}; + + // Specifier type. + const SpecifierType specifier_{}; - // As an indication that this specifier is a %s (expect to be replaced by seconds since the - // epoch). - const bool second_; + // The width of a sub-second specifier, e.g. given %3f, the width is 3. If %f is set as the + // specifier, the width value should be 9 (the number of nanosecond digits). + // The allowed values are: + // 0: only when the specifier is seconds specifier or string specifier. + // 1-9: fixed width of subseconds specifier. + // 255: std::numeric_limits::max(), full subseconds precision with dynamic width. + const uint8_t width_{}; }; - // This holds all specifiers found in a given format string. - std::vector specifiers_; + // A struct to hold the offset and length of a specifier result in the format string. + struct SpecifierOffset { + size_t offset{}; + size_t length{}; + }; + + struct CacheableTime { + std::chrono::seconds epoch_time_seconds; + + std::string formatted; + std::vector offsets; + }; + using CachedTimes = absl::node_hash_map; + + CacheableTime formatTimeAndOffsets(SystemTime time, + std::chrono::seconds epoch_time_seconds) const; // This is the format string as supplied in configuration, e.g. "foo %3f bar". const std::string raw_format_string_; + const size_t raw_format_hash_{}; + + // Use local time zone instead of UTC if this is set to true. + const bool local_time_{}; - // Whether use local time zone. - const bool local_time_; + // This holds all specifiers found in a given format string. + std::vector specifiers_; }; /** diff --git a/source/common/config/datasource.cc b/source/common/config/datasource.cc index 14457b3bff28..c086a2cd9339 100644 --- a/source/common/config/datasource.cc +++ b/source/common/config/datasource.cc @@ -40,7 +40,7 @@ absl::StatusOr readFile(const std::string& path, Api::Api& api, boo } auto file_content_or_error = file_system.fileReadToEnd(path); - RETURN_IF_STATUS_NOT_OK(file_content_or_error); + RETURN_IF_NOT_OK_REF(file_content_or_error.status()); if (!allow_empty && file_content_or_error.value().empty()) { return absl::InvalidArgumentError(fmt::format("file {} is empty", path)); @@ -118,7 +118,7 @@ absl::StatusOr DataSourceProvider::create(const ProtoData Api::Api& api, bool allow_empty, uint64_t max_size) { auto initial_data_or_error = read(source, allow_empty, api, max_size); - RETURN_IF_STATUS_NOT_OK(initial_data_or_error); + RETURN_IF_NOT_OK_REF(initial_data_or_error.status()); // read() only validates the size of the file and does not check the size of inline data. // We check the size of inline data here. diff --git a/source/common/config/well_known_names.cc b/source/common/config/well_known_names.cc index c9b73b1ab089..466e033c33a9 100644 --- a/source/common/config/well_known_names.cc +++ b/source/common/config/well_known_names.cc @@ -26,6 +26,8 @@ std::string expandRegex(const std::string& regex) { // Route names may contain dots and slashes in addition to // alphanumerics, underscores, and dashes. {"", R"([\w-\./]+)"}, + // Scoped Route names are named similarly to route config names. + {"", R"([\w-\.]+)"}, // Match a prefix that is either a listener plus name or cluster plus name {"", R"((?:listener|cluster)\..*?)"}, {"", R"(\d)"}}); @@ -183,6 +185,11 @@ TagNameValues::TagNameValues() { // match. addRe2(RDS_ROUTE_CONFIG, R"(^http\.\.rds\.(()\.)\w+?$)", ".rds."); + // http.[.]scoped_rds.(.) + addRe2(SCOPED_RDS_CONFIG, + R"(^http\.\.scoped_rds\.(()\.)\w+?$)", + ".scoped_rds."); + // vhost.[.]route.(.)* addTokenized(ROUTE, "vhost.*.route.$.**"); diff --git a/source/common/config/well_known_names.h b/source/common/config/well_known_names.h index 334e50cc6aa2..565aa8bcfa27 100644 --- a/source/common/config/well_known_names.h +++ b/source/common/config/well_known_names.h @@ -34,6 +34,9 @@ class MetadataFilterValues { const std::string ENVOY_LB = "envoy.lb"; // Filter namespace for built-in transport socket match in cluster. const std::string ENVOY_TRANSPORT_SOCKET_MATCH = "envoy.transport_socket_match"; + // Proxy address configuration namespace for HTTP/1.1 proxy transport sockets. + const std::string ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR = + "envoy.http11_proxy_transport_socket.proxy_address"; }; using MetadataFilters = ConstSingleton; @@ -153,6 +156,8 @@ class TagNameValues { const std::string RESPONSE_CODE_CLASS = "envoy.response_code_class"; // Route config name for RDS updates const std::string RDS_ROUTE_CONFIG = "envoy.rds_route_config"; + // Scoped route config name for RDS updates + const std::string SCOPED_RDS_CONFIG = "envoy.scoped_rds_config"; // Request route given by the Router http filter const std::string ROUTE = "envoy.route"; // Stats prefix for the ext_authz HTTP filter diff --git a/source/common/filesystem/inotify/watcher_impl.cc b/source/common/filesystem/inotify/watcher_impl.cc index 549798e00bfc..f335c2ad62d3 100644 --- a/source/common/filesystem/inotify/watcher_impl.cc +++ b/source/common/filesystem/inotify/watcher_impl.cc @@ -36,7 +36,7 @@ absl::Status WatcherImpl::addWatch(absl::string_view path, uint32_t events, OnCh // Because of general inotify pain, we always watch the directory that the file lives in, // and then synthetically raise per file events. auto result_or_error = file_system_.splitPathFromFilename(path); - RETURN_IF_STATUS_NOT_OK(result_or_error); + RETURN_IF_NOT_OK_REF(result_or_error.status()); const PathSplitResult result = result_or_error.value(); const uint32_t watch_mask = IN_MODIFY | IN_MOVED_TO; @@ -54,7 +54,10 @@ absl::Status WatcherImpl::addWatch(absl::string_view path, uint32_t events, OnCh absl::Status WatcherImpl::onInotifyEvent() { while (true) { - uint8_t buffer[sizeof(inotify_event) + NAME_MAX + 1]; + // The buffer needs to be suitably aligned to store the first inotify_event structure. + // If there are multiple events returned by the read call, the kernel is responsible for + // properly aligning subsequent inotify_event structures (per `man inotify`). + alignas(inotify_event) uint8_t buffer[sizeof(inotify_event) + NAME_MAX + 1]; ssize_t rc = read(inotify_fd_, &buffer, sizeof(buffer)); if (rc == -1 && errno == EAGAIN) { return absl::OkStatus(); diff --git a/source/common/filesystem/kqueue/watcher_impl.cc b/source/common/filesystem/kqueue/watcher_impl.cc index 507cfcd8aab4..5827c19590ae 100644 --- a/source/common/filesystem/kqueue/watcher_impl.cc +++ b/source/common/filesystem/kqueue/watcher_impl.cc @@ -36,7 +36,7 @@ WatcherImpl::~WatcherImpl() { absl::Status WatcherImpl::addWatch(absl::string_view path, uint32_t events, Watcher::OnChangedCb cb) { absl::StatusOr watch_or_error = addWatch(path, events, cb, false); - RETURN_IF_STATUS_NOT_OK(watch_or_error); + RETURN_IF_NOT_OK_REF(watch_or_error.status()); if (watch_or_error.value() == nullptr) { return absl::InvalidArgumentError(absl::StrCat("invalid watch path ", path)); } @@ -56,7 +56,7 @@ absl::StatusOr WatcherImpl::addWatch(absl::string_vie } const auto result_or_error = file_system_.splitPathFromFilename(path); - RETURN_IF_STATUS_NOT_OK(result_or_error); + RETURN_IF_NOT_OK_REF(result_or_error.status()); watch_fd = open(std::string(result_or_error.value().directory_).c_str(), 0); if (watch_fd == -1) { return nullptr; @@ -116,7 +116,7 @@ absl::Status WatcherImpl::onKqueueEvent() { absl::StatusOr pathname_or_error = file_system_.splitPathFromFilename(file->file_); - RETURN_IF_STATUS_NOT_OK(pathname_or_error); + RETURN_IF_NOT_OK_REF(pathname_or_error.status()); PathSplitResult& pathname = pathname_or_error.value(); if (file->watching_dir_) { @@ -129,7 +129,7 @@ absl::Status WatcherImpl::onKqueueEvent() { if (event.fflags & NOTE_WRITE) { // directory was written -- check if the file we're actually watching appeared auto file_or_error = addWatch(file->file_, file->events_, file->callback_, true); - RETURN_IF_STATUS_NOT_OK(file_or_error); + RETURN_IF_NOT_OK_REF(file_or_error.status()); FileWatchPtr new_file = file_or_error.value(); if (new_file != nullptr) { removeWatch(file); @@ -150,7 +150,7 @@ absl::Status WatcherImpl::onKqueueEvent() { removeWatch(file); auto file_or_error = addWatch(file->file_, file->events_, file->callback_, true); - RETURN_IF_STATUS_NOT_OK(file_or_error); + RETURN_IF_NOT_OK_REF(file_or_error.status()); FileWatchPtr new_file = file_or_error.value(); if (new_file == nullptr) { return absl::OkStatus(); diff --git a/source/common/filesystem/win32/watcher_impl.cc b/source/common/filesystem/win32/watcher_impl.cc index 6cb9d00a1bc7..58905d996d22 100644 --- a/source/common/filesystem/win32/watcher_impl.cc +++ b/source/common/filesystem/win32/watcher_impl.cc @@ -56,7 +56,7 @@ absl::Status WatcherImpl::addWatch(absl::string_view path, uint32_t events, OnCh } const absl::StatusOr result_or_error = file_system_.splitPathFromFilename(path); - RETURN_IF_STATUS_NOT_OK(result_or_error); + RETURN_IF_NOT_OK_REF(result_or_error.status()); const PathSplitResult& result = result_or_error.value(); // ReadDirectoryChangesW only has a Unicode version, so we need // to use wide strings here diff --git a/source/common/filter/config_discovery_impl.h b/source/common/filter/config_discovery_impl.h index 1aaec8a0ab3d..7d0cb1c3f7b8 100644 --- a/source/common/filter/config_discovery_impl.h +++ b/source/common/filter/config_discovery_impl.h @@ -111,7 +111,7 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa absl::Status onConfigUpdate(const Protobuf::Message& message, const std::string&, Config::ConfigAppliedCb applied_on_all_threads) override { const absl::StatusOr config_or_error = instantiateFilterFactory(message); - RETURN_IF_STATUS_NOT_OK(config_or_error); + RETURN_IF_NOT_OK_REF(config_or_error.status()); update(config_or_error.value(), applied_on_all_threads); return absl::OkStatus(); } @@ -120,7 +120,7 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa absl::optional cb; if (default_configuration_) { auto cb_or_error = instantiateFilterFactory(*default_configuration_); - RETURN_IF_STATUS_NOT_OK(cb_or_error); + RETURN_IF_NOT_OK_REF(cb_or_error.status()); cb = cb_or_error.value(); } update(cb, applied_on_all_threads); @@ -181,20 +181,14 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBa const ProtobufTypes::MessagePtr default_configuration_; }; -// Struct of canonical filter name and HTTP stream filter factory callback. -struct NamedHttpFilterFactoryCb { - // Canonical filter name. - std::string name; - // Factory function used to create filter instances. - Http::FilterFactoryCb factory_cb; -}; +using HttpFilterFactoryCb = Http::FilterFactoryCb; // Implementation of a HTTP dynamic filter config provider. // NeutralHttpFilterConfigFactory can either be a NamedHttpFilterConfigFactory // or an UpstreamHttpFilterConfigFactory. template class HttpDynamicFilterConfigProviderImpl - : public DynamicFilterConfigProviderImpl { + : public DynamicFilterConfigProviderImpl { public: HttpDynamicFilterConfigProviderImpl( FilterConfigSubscriptionSharedPtr& subscription, @@ -219,14 +213,11 @@ class HttpDynamicFilterConfigProviderImpl } private: - absl::StatusOr + absl::StatusOr instantiateFilterFactory(const Protobuf::Message& message) const override { auto* factory = Registry::FactoryRegistry::getFactoryByType( message.GetTypeName()); - absl::StatusOr error_or_factory = - factory->createFilterFactoryFromProto(message, getStatPrefix(), factory_context_); - RETURN_IF_STATUS_NOT_OK(error_or_factory); - return NamedHttpFilterFactoryCb{factory->name(), error_or_factory.value()}; + return factory->createFilterFactoryFromProto(message, getStatPrefix(), factory_context_); } Server::Configuration::ServerFactoryContext& server_context_; @@ -257,7 +248,7 @@ class NetworkDynamicFilterConfigProviderImplBase message.GetTypeName()); absl::StatusOr cb_or_error = factory->createFilterFactoryFromProto(message, factory_context_); - RETURN_IF_STATUS_NOT_OK(cb_or_error); + RETURN_IF_NOT_OK_REF(cb_or_error.status()); return cb_or_error.value(); } @@ -651,7 +642,7 @@ class FilterConfigProviderManagerImpl : public FilterConfigProviderManagerImplBa // HTTP filter class HttpFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl< - Server::Configuration::NamedHttpFilterConfigFactory, NamedHttpFilterFactoryCb, + Server::Configuration::NamedHttpFilterConfigFactory, HttpFilterFactoryCb, Server::Configuration::FactoryContext, HttpDynamicFilterConfigProviderImpl< Server::Configuration::FactoryContext, @@ -679,7 +670,7 @@ class HttpFilterConfigProviderManagerImpl // HTTP filter class UpstreamHttpFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl< - Server::Configuration::UpstreamHttpFilterConfigFactory, NamedHttpFilterFactoryCb, + Server::Configuration::UpstreamHttpFilterConfigFactory, HttpFilterFactoryCb, Server::Configuration::UpstreamFactoryContext, HttpDynamicFilterConfigProviderImpl< Server::Configuration::UpstreamFactoryContext, diff --git a/source/common/formatter/http_specific_formatter.cc b/source/common/formatter/http_specific_formatter.cc index 8cafea9d7c2a..a46c9559c9f5 100644 --- a/source/common/formatter/http_specific_formatter.cc +++ b/source/common/formatter/http_specific_formatter.cc @@ -42,8 +42,8 @@ AccessLogTypeFormatter::formatValueWithContext(const HttpFormatterContext& conte return ValueUtil::stringValue(AccessLogType_Name(context.accessLogType())); } -HeaderFormatter::HeaderFormatter(const std::string& main_header, - const std::string& alternative_header, +HeaderFormatter::HeaderFormatter(absl::string_view main_header, + absl::string_view alternative_header, absl::optional max_length) : main_header_(main_header), alternative_header_(alternative_header), max_length_(max_length) {} @@ -81,8 +81,8 @@ ProtobufWkt::Value HeaderFormatter::formatValue(const Http::HeaderMap& headers) return ValueUtil::stringValue(std::string(val)); } -ResponseHeaderFormatter::ResponseHeaderFormatter(const std::string& main_header, - const std::string& alternative_header, +ResponseHeaderFormatter::ResponseHeaderFormatter(absl::string_view main_header, + absl::string_view alternative_header, absl::optional max_length) : HeaderFormatter(main_header, alternative_header, max_length) {} @@ -98,8 +98,8 @@ ResponseHeaderFormatter::formatValueWithContext(const HttpFormatterContext& cont return HeaderFormatter::formatValue(context.responseHeaders()); } -RequestHeaderFormatter::RequestHeaderFormatter(const std::string& main_header, - const std::string& alternative_header, +RequestHeaderFormatter::RequestHeaderFormatter(absl::string_view main_header, + absl::string_view alternative_header, absl::optional max_length) : HeaderFormatter(main_header, alternative_header, max_length) {} @@ -115,8 +115,8 @@ RequestHeaderFormatter::formatValueWithContext(const HttpFormatterContext& conte return HeaderFormatter::formatValue(context.requestHeaders()); } -ResponseTrailerFormatter::ResponseTrailerFormatter(const std::string& main_header, - const std::string& alternative_header, +ResponseTrailerFormatter::ResponseTrailerFormatter(absl::string_view main_header, + absl::string_view alternative_header, absl::optional max_length) : HeaderFormatter(main_header, alternative_header, max_length) {} @@ -194,8 +194,7 @@ GrpcStatusFormatter::Format GrpcStatusFormatter::parseFormat(absl::string_view f return GrpcStatusFormatter::Number; } - throwEnvoyExceptionOrPanic( - "GrpcStatusFormatter only supports CAMEL_STRING, SNAKE_STRING or NUMBER."); + throw EnvoyException("GrpcStatusFormatter only supports CAMEL_STRING, SNAKE_STRING or NUMBER."); } GrpcStatusFormatter::GrpcStatusFormatter(const std::string& main_header, @@ -299,96 +298,85 @@ BuiltInHttpCommandParser::getKnownFormatters() { FormatterProviderLookupTbl, {{"REQ", {CommandSyntaxChecker::PARAMS_REQUIRED | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional& max_length) { - std::string main_header, alternative_header; - - THROW_IF_NOT_OK(SubstitutionFormatUtils::parseSubcommandHeaders(format, main_header, - alternative_header)); - - return std::make_unique(main_header, alternative_header, - max_length); + [](absl::string_view format, absl::optional max_length) { + auto result = SubstitutionFormatUtils::parseSubcommandHeaders(format); + THROW_IF_STATUS_NOT_OK(result, throw); + return std::make_unique(result.value().first, + result.value().second, max_length); }}}, {"RESP", {CommandSyntaxChecker::PARAMS_REQUIRED | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional& max_length) { - std::string main_header, alternative_header; - - THROW_IF_NOT_OK(SubstitutionFormatUtils::parseSubcommandHeaders(format, main_header, - alternative_header)); - - return std::make_unique(main_header, alternative_header, - max_length); + [](absl::string_view format, absl::optional max_length) { + auto result = SubstitutionFormatUtils::parseSubcommandHeaders(format); + THROW_IF_STATUS_NOT_OK(result, throw); + return std::make_unique(result.value().first, + result.value().second, max_length); }}}, {"TRAILER", {CommandSyntaxChecker::PARAMS_REQUIRED | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional& max_length) { - std::string main_header, alternative_header; - - THROW_IF_NOT_OK(SubstitutionFormatUtils::parseSubcommandHeaders(format, main_header, - alternative_header)); - - return std::make_unique(main_header, alternative_header, - max_length); + [](absl::string_view format, absl::optional max_length) { + auto result = SubstitutionFormatUtils::parseSubcommandHeaders(format); + THROW_IF_STATUS_NOT_OK(result, throw); + return std::make_unique(result.value().first, + result.value().second, max_length); }}}, {"LOCAL_REPLY_BODY", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique(); }}}, {"ACCESS_LOG_TYPE", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique(); }}}, {"GRPC_STATUS", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, const absl::optional&) { + [](absl::string_view format, absl::optional) { return std::make_unique("grpc-status", "", absl::optional(), GrpcStatusFormatter::parseFormat(format)); }}}, {"GRPC_STATUS_NUMBER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, const absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique("grpc-status", "", absl::optional(), GrpcStatusFormatter::Number); }}}, {"REQUEST_HEADERS_BYTES", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique( HeadersByteSizeFormatter::HeaderType::RequestHeaders); }}}, {"RESPONSE_HEADERS_BYTES", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique( HeadersByteSizeFormatter::HeaderType::ResponseHeaders); }}}, {"RESPONSE_TRAILERS_BYTES", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional&) { + [](absl::string_view, absl::optional) { return std::make_unique( HeadersByteSizeFormatter::HeaderType::ResponseTrailers); }}}, {"STREAM_INFO_REQ", {CommandSyntaxChecker::PARAMS_REQUIRED | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional& max_length) { - std::string main_header, alternative_header; - THROW_IF_NOT_OK(SubstitutionFormatUtils::parseSubcommandHeaders(format, main_header, - alternative_header)); - - return std::make_unique(main_header, alternative_header, - max_length); + [](absl::string_view format, absl::optional max_length) { + auto result = SubstitutionFormatUtils::parseSubcommandHeaders(format); + THROW_IF_STATUS_NOT_OK(result, throw); + return std::make_unique(result.value().first, + result.value().second, max_length); }}}, {"TRACE_ID", - {CommandSyntaxChecker::COMMAND_ONLY, [](const std::string&, absl::optional&) { + {CommandSyntaxChecker::COMMAND_ONLY, [](absl::string_view, absl::optional) { return std::make_unique(); }}}}); } -FormatterProviderPtr BuiltInHttpCommandParser::parse(const std::string& command, - const std::string& subcommand, - absl::optional& max_length) const { +FormatterProviderPtr BuiltInHttpCommandParser::parse(absl::string_view command, + absl::string_view subcommand, + absl::optional max_length) const { const FormatterProviderLookupTbl& providers = getKnownFormatters(); auto it = providers.find(command); diff --git a/source/common/formatter/http_specific_formatter.h b/source/common/formatter/http_specific_formatter.h index 34dc7958cf89..0afd9327781d 100644 --- a/source/common/formatter/http_specific_formatter.h +++ b/source/common/formatter/http_specific_formatter.h @@ -53,7 +53,7 @@ class AccessLogTypeFormatter : public FormatterProvider { class HeaderFormatter { public: - HeaderFormatter(const std::string& main_header, const std::string& alternative_header, + HeaderFormatter(absl::string_view main_header, absl::string_view alternative_header, absl::optional max_length); protected: @@ -97,7 +97,7 @@ class HeadersByteSizeFormatter : public FormatterProvider { */ class RequestHeaderFormatter : public FormatterProvider, HeaderFormatter { public: - RequestHeaderFormatter(const std::string& main_header, const std::string& alternative_header, + RequestHeaderFormatter(absl::string_view main_header, absl::string_view alternative_header, absl::optional max_length); // FormatterProvider @@ -114,7 +114,7 @@ class RequestHeaderFormatter : public FormatterProvider, HeaderFormatter { */ class ResponseHeaderFormatter : public FormatterProvider, HeaderFormatter { public: - ResponseHeaderFormatter(const std::string& main_header, const std::string& alternative_header, + ResponseHeaderFormatter(absl::string_view main_header, absl::string_view alternative_header, absl::optional max_length); // FormatterProvider @@ -131,7 +131,7 @@ class ResponseHeaderFormatter : public FormatterProvider, HeaderFormatter { */ class ResponseTrailerFormatter : public FormatterProvider, HeaderFormatter { public: - ResponseTrailerFormatter(const std::string& main_header, const std::string& alternative_header, + ResponseTrailerFormatter(absl::string_view main_header, absl::string_view alternative_header, absl::optional max_length); // FormatterProvider @@ -205,12 +205,12 @@ class BuiltInHttpCommandParser : public CommandParser { BuiltInHttpCommandParser() = default; // CommandParser - FormatterProviderPtr parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const override; + FormatterProviderPtr parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const override; private: using FormatterProviderCreateFunc = - std::function&)>; + std::function)>; using FormatterProviderLookupTbl = absl::flat_hash_map - #include "source/common/common/random_generator.h" #include "source/common/config/metadata.h" #include "source/common/http/utility.h" @@ -10,6 +8,7 @@ #include "absl/strings/str_format.h" #include "absl/strings/str_replace.h" +#include "re2/re2.h" namespace Envoy { namespace Formatter { @@ -18,8 +17,8 @@ namespace { static const std::string DefaultUnspecifiedValueString = "-"; -const std::regex& getSystemTimeFormatNewlinePattern() { - CONSTRUCT_ON_FIRST_USE(std::regex, "%[-_0^#]*[1-9]*(E|O)?n"); +const re2::RE2& getSystemTimeFormatNewlinePattern() { + CONSTRUCT_ON_FIRST_USE(re2::RE2, "%[-_0^#]*[1-9]*(E|O)?n"); } Network::Address::InstanceConstSharedPtr @@ -47,11 +46,11 @@ getUpstreamRemoteAddress(const StreamInfo::StreamInfo& stream_info) { } // namespace -MetadataFormatter::MetadataFormatter(const std::string& filter_namespace, - const std::vector& path, +MetadataFormatter::MetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length, MetadataFormatter::GetMetadataFunction get_func) - : filter_namespace_(filter_namespace), path_(path), max_length_(max_length), + : filter_namespace_(filter_namespace), path_(path.begin(), path.end()), max_length_(max_length), get_func_(get_func) {} absl::optional @@ -116,16 +115,16 @@ ProtobufWkt::Value MetadataFormatter::formatValue(const StreamInfo::StreamInfo& // TODO(glicht): Consider adding support for route/listener/cluster metadata as suggested by // @htuch. See: https://github.com/envoyproxy/envoy/issues/3006 -DynamicMetadataFormatter::DynamicMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, +DynamicMetadataFormatter::DynamicMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length) : MetadataFormatter(filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) { return &stream_info.dynamicMetadata(); }) {} -ClusterMetadataFormatter::ClusterMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, +ClusterMetadataFormatter::ClusterMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length) : MetadataFormatter(filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) @@ -137,9 +136,9 @@ ClusterMetadataFormatter::ClusterMetadataFormatter(const std::string& filter_nam return &cluster_info.value()->metadata(); }) {} -UpstreamHostMetadataFormatter::UpstreamHostMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) +UpstreamHostMetadataFormatter::UpstreamHostMetadataFormatter( + absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) : MetadataFormatter(filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) -> const envoy::config::core::v3::Metadata* { @@ -155,29 +154,29 @@ UpstreamHostMetadataFormatter::UpstreamHostMetadataFormatter(const std::string& }) {} std::unique_ptr -FilterStateFormatter::create(const std::string& format, const absl::optional& max_length, +FilterStateFormatter::create(absl::string_view format, absl::optional max_length, bool is_upstream) { - std::string key, serialize_type, field_name; + absl::string_view key, serialize_type, field_name; static constexpr absl::string_view PLAIN_SERIALIZATION{"PLAIN"}; static constexpr absl::string_view TYPED_SERIALIZATION{"TYPED"}; static constexpr absl::string_view FIELD_SERIALIZATION{"FIELD"}; SubstitutionFormatUtils::parseSubcommand(format, ':', key, serialize_type, field_name); if (key.empty()) { - throwEnvoyExceptionOrPanic("Invalid filter state configuration, key cannot be empty."); + throw EnvoyException("Invalid filter state configuration, key cannot be empty."); } if (serialize_type.empty()) { - serialize_type = std::string(TYPED_SERIALIZATION); + serialize_type = TYPED_SERIALIZATION; } if (serialize_type != PLAIN_SERIALIZATION && serialize_type != TYPED_SERIALIZATION && serialize_type != FIELD_SERIALIZATION) { - throwEnvoyExceptionOrPanic("Invalid filter state serialize type, only " - "support PLAIN/TYPED/FIELD."); + throw EnvoyException("Invalid filter state serialize type, only " + "support PLAIN/TYPED/FIELD."); } if ((serialize_type == FIELD_SERIALIZATION) ^ !field_name.empty()) { - throwEnvoyExceptionOrPanic("Invalid filter state serialize type, FIELD " - "should be used with the field name."); + throw EnvoyException("Invalid filter state serialize type, FIELD " + "should be used with the field name."); } const bool serialize_as_string = serialize_type == PLAIN_SERIALIZATION; @@ -186,14 +185,13 @@ FilterStateFormatter::create(const std::string& format, const absl::optional max_length, +FilterStateFormatter::FilterStateFormatter(absl::string_view key, absl::optional max_length, bool serialize_as_string, bool is_upstream, - const std::string& field_name) + absl::string_view field_name) : key_(key), max_length_(max_length), is_upstream_(is_upstream) { if (!field_name.empty()) { format_ = FilterStateFormat::Field; - field_name_ = field_name; + field_name_ = std::string(field_name); factory_ = Registry::FactoryRegistry::getFactory(key); } else if (serialize_as_string) { format_ = FilterStateFormat::String; @@ -423,8 +421,7 @@ CommonDurationFormatter::create(absl::string_view sub_command) { absl::InlinedVector parsed_sub_commands = absl::StrSplit(sub_command, ':'); if (parsed_sub_commands.size() < 2 || parsed_sub_commands.size() > 3) { - throwEnvoyExceptionOrPanic( - fmt::format("Invalid common duration configuration: {}.", sub_command)); + throw EnvoyException(fmt::format("Invalid common duration configuration: {}.", sub_command)); } absl::string_view start = parsed_sub_commands[0]; @@ -442,8 +439,7 @@ CommonDurationFormatter::create(absl::string_view sub_command) { } else if (precision_str == NanosecondsPrecision) { precision = DurationPrecision::Nanoseconds; } else { - throwEnvoyExceptionOrPanic( - fmt::format("Invalid common duration precision: {}.", precision_str)); + throw EnvoyException(fmt::format("Invalid common duration precision: {}.", precision_str)); } } @@ -498,14 +494,14 @@ ProtobufWkt::Value CommonDurationFormatter::formatValue(const StreamInfo::Stream // A SystemTime formatter that extracts the startTime from StreamInfo. Must be provided // an access log command that starts with `START_TIME`. -StartTimeFormatter::StartTimeFormatter(const std::string& format) +StartTimeFormatter::StartTimeFormatter(absl::string_view format) : SystemTimeFormatter( format, std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { return stream_info.startTime(); })) {} -DownstreamPeerCertVStartFormatter::DownstreamPeerCertVStartFormatter(const std::string& format) +DownstreamPeerCertVStartFormatter::DownstreamPeerCertVStartFormatter(absl::string_view format) : SystemTimeFormatter( format, std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { @@ -515,7 +511,7 @@ DownstreamPeerCertVStartFormatter::DownstreamPeerCertVStartFormatter(const std:: ? connection_info->validFromPeerCertificate() : absl::optional(); })) {} -DownstreamPeerCertVEndFormatter::DownstreamPeerCertVEndFormatter(const std::string& format) +DownstreamPeerCertVEndFormatter::DownstreamPeerCertVEndFormatter(absl::string_view format) : SystemTimeFormatter( format, std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { @@ -525,7 +521,7 @@ DownstreamPeerCertVEndFormatter::DownstreamPeerCertVEndFormatter(const std::stri ? connection_info->expirationPeerCertificate() : absl::optional(); })) {} -UpstreamPeerCertVStartFormatter::UpstreamPeerCertVStartFormatter(const std::string& format) +UpstreamPeerCertVStartFormatter::UpstreamPeerCertVStartFormatter(absl::string_view format) : SystemTimeFormatter( format, std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { @@ -537,7 +533,7 @@ UpstreamPeerCertVStartFormatter::UpstreamPeerCertVStartFormatter(const std::stri ->validFromPeerCertificate() : absl::optional(); })) {} -UpstreamPeerCertVEndFormatter::UpstreamPeerCertVEndFormatter(const std::string& format) +UpstreamPeerCertVEndFormatter::UpstreamPeerCertVEndFormatter(absl::string_view format) : SystemTimeFormatter( format, std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { @@ -550,14 +546,14 @@ UpstreamPeerCertVEndFormatter::UpstreamPeerCertVEndFormatter(const std::string& : absl::optional(); })) {} -SystemTimeFormatter::SystemTimeFormatter(const std::string& format, TimeFieldExtractorPtr f, +SystemTimeFormatter::SystemTimeFormatter(absl::string_view format, TimeFieldExtractorPtr f, bool local_time) : date_formatter_(format, local_time), time_field_extractor_(std::move(f)), local_time_(local_time) { // Validate the input specifier here. The formatted string may be destined for a header, and // should not contain invalid characters {NUL, LR, CF}. - if (std::regex_search(format, getSystemTimeFormatNewlinePattern())) { - throwEnvoyExceptionOrPanic("Invalid header configuration. Format string contains newline."); + if (re2::RE2::PartialMatch(format, getSystemTimeFormatNewlinePattern())) { + throw EnvoyException("Invalid header configuration. Format string contains newline."); } } @@ -578,11 +574,12 @@ SystemTimeFormatter::formatValue(const StreamInfo::StreamInfo& stream_info) cons return ValueUtil::optionalStringValue(format(stream_info)); } -EnvironmentFormatter::EnvironmentFormatter(const std::string& key, +EnvironmentFormatter::EnvironmentFormatter(absl::string_view key, absl::optional max_length) { ASSERT(!key.empty()); - const char* env_value = std::getenv(key.c_str()); + const std::string key_str = std::string(key); + const char* env_value = std::getenv(key_str.c_str()); if (env_value != nullptr) { std::string env_string = env_value; SubstitutionFormatUtils::truncate(env_string, max_length); @@ -830,7 +827,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide { {"REQUEST_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -839,7 +836,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"REQUEST_TX_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -848,7 +845,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"RESPONSE_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -857,7 +854,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"RESPONSE_TX_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -874,7 +871,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_HANDSHAKE_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -883,7 +880,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"ROUNDTRIP_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { StreamInfo::TimingUtility timing(stream_info); @@ -892,7 +889,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"BYTES_RECEIVED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.bytesReceived(); @@ -900,7 +897,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"BYTES_RETRANSMITTED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.bytesRetransmitted(); @@ -908,7 +905,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"PACKETS_RETRANSMITTED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.packetsRetransmitted(); @@ -916,7 +913,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_WIRE_BYTES_RECEIVED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getUpstreamBytesMeter(); @@ -925,7 +922,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_HEADER_BYTES_RECEIVED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getUpstreamBytesMeter(); @@ -934,7 +931,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_WIRE_BYTES_RECEIVED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getDownstreamBytesMeter(); @@ -943,7 +940,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_HEADER_BYTES_RECEIVED", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getDownstreamBytesMeter(); @@ -952,7 +949,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"PROTOCOL", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return SubstitutionFormatUtils::protocolToString(stream_info.protocol()); @@ -960,7 +957,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PROTOCOL", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.upstreamInfo() @@ -971,7 +968,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"RESPONSE_CODE", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.responseCode().value_or(0); @@ -979,7 +976,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"RESPONSE_CODE_DETAILS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.responseCodeDetails(); @@ -987,7 +984,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"CONNECTION_TERMINATION_DETAILS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.connectionTerminationDetails(); @@ -995,7 +992,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"BYTES_SENT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.bytesSent(); @@ -1003,7 +1000,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_WIRE_BYTES_SENT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getUpstreamBytesMeter(); @@ -1012,7 +1009,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_HEADER_BYTES_SENT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getUpstreamBytesMeter(); @@ -1021,7 +1018,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_WIRE_BYTES_SENT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getDownstreamBytesMeter(); @@ -1030,7 +1027,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_HEADER_BYTES_SENT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { const auto& bytes_meter = stream_info.getDownstreamBytesMeter(); @@ -1039,7 +1036,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.currentDuration(); @@ -1047,12 +1044,12 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"COMMON_DURATION", {CommandSyntaxChecker::PARAMS_REQUIRED, - [](const std::string& sub_command, absl::optional) { + [](absl::string_view sub_command, absl::optional) { return CommonDurationFormatter::create(sub_command); }}}, {"RESPONSE_FLAGS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return StreamInfo::ResponseFlagUtils::toShortString(stream_info); @@ -1060,7 +1057,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"RESPONSE_FLAGS_LONG", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return StreamInfo::ResponseFlagUtils::toString(stream_info); @@ -1068,7 +1065,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_HOST_NAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { const auto opt_ref = stream_info.upstreamInfo(); @@ -1089,7 +1086,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_HOST", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1106,7 +1103,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_CONNECTION_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { uint64_t upstream_connection_id = 0; @@ -1119,7 +1116,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_CLUSTER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { std::string upstream_cluster_name; @@ -1136,7 +1133,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_CLUSTER_RAW", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { std::string upstream_cluster_name; @@ -1152,7 +1149,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_ADDRESS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1164,7 +1161,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withoutPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1176,7 +1173,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::justPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1188,7 +1185,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_REMOTE_ADDRESS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1197,7 +1194,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withoutPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1206,7 +1203,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_REMOTE_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::justPort( [](const StreamInfo::StreamInfo& stream_info) -> Network::Address::InstanceConstSharedPtr { @@ -1215,7 +1212,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_REQUEST_ATTEMPT_COUNT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.attemptCount().value_or(0); @@ -1223,7 +1220,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_TLS_CIPHER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.ciphersuiteString(); @@ -1231,7 +1228,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_TLS_VERSION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.tlsVersion(); @@ -1239,7 +1236,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_TLS_SESSION_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.sessionId(); @@ -1247,7 +1244,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_ISSUER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.issuerPeerCertificate(); @@ -1255,7 +1252,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_CERT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.urlEncodedPemEncodedPeerCertificate(); @@ -1263,7 +1260,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_SUBJECT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.subjectPeerCertificate(); @@ -1271,7 +1268,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_ADDRESS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().localAddress(); @@ -1279,7 +1276,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withoutPort( [](const Envoy::StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().localAddress(); @@ -1287,7 +1284,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::justPort( [](const Envoy::StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().localAddress(); @@ -1295,7 +1292,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_REMOTE_ADDRESS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().remoteAddress(); @@ -1303,7 +1300,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withoutPort( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().remoteAddress(); @@ -1311,7 +1308,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_REMOTE_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::justPort( [](const Envoy::StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().remoteAddress(); @@ -1319,7 +1316,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_DIRECT_REMOTE_ADDRESS", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withPort( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().directRemoteAddress(); @@ -1327,7 +1324,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::withoutPort( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().directRemoteAddress(); @@ -1335,7 +1332,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_DIRECT_REMOTE_PORT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return StreamInfoAddressFormatterProvider::justPort( [](const Envoy::StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().directRemoteAddress(); @@ -1343,7 +1340,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"CONNECTION_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().connectionID().value_or(0); @@ -1351,7 +1348,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"REQUESTED_SERVER_NAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { absl::optional result; @@ -1364,7 +1361,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"ROUTE_NAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { absl::optional result; @@ -1377,7 +1374,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_URI_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.uriSanPeerCertificate(), ","); @@ -1385,7 +1382,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_DNS_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.dnsSansPeerCertificate(), ","); @@ -1393,7 +1390,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_PEER_IP_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.ipSansPeerCertificate(), ","); @@ -1401,7 +1398,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_URI_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.uriSanLocalCertificate(), ","); @@ -1409,7 +1406,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_DNS_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.dnsSansLocalCertificate(), ","); @@ -1417,7 +1414,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_LOCAL_IP_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.ipSansLocalCertificate(), ","); @@ -1425,7 +1422,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_URI_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.uriSanPeerCertificate(), ","); @@ -1433,7 +1430,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_DNS_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.dnsSansPeerCertificate(), ","); @@ -1441,7 +1438,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_IP_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.ipSansPeerCertificate(), ","); @@ -1449,7 +1446,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_URI_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.uriSanLocalCertificate(), ","); @@ -1457,7 +1454,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_DNS_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.dnsSansLocalCertificate(), ","); @@ -1465,7 +1462,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_IP_SAN", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return absl::StrJoin(connection_info.ipSansLocalCertificate(), ","); @@ -1473,7 +1470,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_SUBJECT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.subjectPeerCertificate(); @@ -1481,7 +1478,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_LOCAL_SUBJECT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.subjectLocalCertificate(); @@ -1489,7 +1486,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_TLS_SESSION_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.sessionId(); @@ -1497,7 +1494,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_TLS_CIPHER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.ciphersuiteString(); @@ -1505,7 +1502,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_TLS_VERSION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.tlsVersion(); @@ -1513,7 +1510,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_FINGERPRINT_256", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.sha256PeerCertificateDigest(); @@ -1521,7 +1518,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_FINGERPRINT_1", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.sha1PeerCertificateDigest(); @@ -1529,15 +1526,39 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_SERIAL", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.serialNumberPeerCertificate(); }); }}}, + {"DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256", + {CommandSyntaxChecker::COMMAND_ONLY, + [](const absl::string_view, absl::optional) { + return std::make_unique( + [](const Ssl::ConnectionInfo& connection_info) { + return absl::StrJoin(connection_info.sha256PeerCertificateChainDigests(), ","); + }); + }}}, + {"DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1", + {CommandSyntaxChecker::COMMAND_ONLY, + [](const absl::string_view, absl::optional) { + return std::make_unique( + [](const Ssl::ConnectionInfo& connection_info) { + return absl::StrJoin(connection_info.sha1PeerCertificateChainDigests(), ","); + }); + }}}, + {"DOWNSTREAM_PEER_CHAIN_SERIALS", + {CommandSyntaxChecker::COMMAND_ONLY, + [](const absl::string_view, absl::optional) { + return std::make_unique( + [](const Ssl::ConnectionInfo& connection_info) { + return absl::StrJoin(connection_info.serialNumbersPeerCertificates(), ","); + }); + }}}, {"DOWNSTREAM_PEER_ISSUER", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.issuerPeerCertificate(); @@ -1545,7 +1566,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_PEER_CERT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const Ssl::ConnectionInfo& connection_info) { return connection_info.urlEncodedPemEncodedPeerCertificate(); @@ -1553,7 +1574,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DOWNSTREAM_TRANSPORT_FAILURE_REASON", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { absl::optional result; @@ -1566,7 +1587,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UPSTREAM_TRANSPORT_FAILURE_REASON", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { absl::optional result; @@ -1587,14 +1608,14 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"HOSTNAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { absl::optional hostname = SubstitutionFormatUtils::getHostname(); return std::make_unique( [hostname](const StreamInfo::StreamInfo&) { return hostname; }); }}}, {"FILTER_CHAIN_NAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { if (const auto info = stream_info.downstreamAddressProvider().filterChainInfo(); @@ -1608,7 +1629,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"VIRTUAL_CLUSTER_NAME", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { return stream_info.virtualClusterName(); @@ -1616,7 +1637,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"TLS_JA3_FINGERPRINT", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) { absl::optional result; @@ -1628,7 +1649,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"UNIQUE_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, const absl::optional&) { + [](absl::string_view, const absl::optional&) { return std::make_unique( [](const StreamInfo::StreamInfo&) -> absl::optional { return absl::make_optional(Random::RandomUtility::uuid()); @@ -1636,7 +1657,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"STREAM_ID", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, absl::optional) { + [](absl::string_view, absl::optional) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { auto provider = stream_info.getStreamIdProvider(); @@ -1652,7 +1673,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"START_TIME", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique( format, std::make_unique( @@ -1662,7 +1683,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"START_TIME_LOCAL", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique( format, std::make_unique( @@ -1673,7 +1694,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"EMIT_TIME", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique( format, std::make_unique( @@ -1683,7 +1704,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"EMIT_TIME_LOCAL", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique( format, std::make_unique( @@ -1694,9 +1715,9 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"DYNAMIC_METADATA", {CommandSyntaxChecker::PARAMS_REQUIRED, - [](const std::string& format, absl::optional max_length) { - std::string filter_namespace; - std::vector path; + [](absl::string_view format, absl::optional max_length) { + absl::string_view filter_namespace; + std::vector path; SubstitutionFormatUtils::parseSubcommand(format, ':', filter_namespace, path); return std::make_unique(filter_namespace, path, max_length); @@ -1704,18 +1725,18 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide {"CLUSTER_METADATA", {CommandSyntaxChecker::PARAMS_REQUIRED, - [](const std::string& format, absl::optional max_length) { - std::string filter_namespace; - std::vector path; + [](absl::string_view format, absl::optional max_length) { + absl::string_view filter_namespace; + std::vector path; SubstitutionFormatUtils::parseSubcommand(format, ':', filter_namespace, path); return std::make_unique(filter_namespace, path, max_length); }}}, {"UPSTREAM_METADATA", {CommandSyntaxChecker::PARAMS_REQUIRED, - [](const std::string& format, absl::optional max_length) { - std::string filter_namespace; - std::vector path; + [](absl::string_view format, absl::optional max_length) { + absl::string_view filter_namespace; + std::vector path; SubstitutionFormatUtils::parseSubcommand(format, ':', filter_namespace, path); return std::make_unique(filter_namespace, path, @@ -1723,42 +1744,42 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide }}}, {"FILTER_STATE", {CommandSyntaxChecker::PARAMS_OPTIONAL | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional max_length) { + [](absl::string_view format, absl::optional max_length) { return FilterStateFormatter::create(format, max_length, false); }}}, {"UPSTREAM_FILTER_STATE", {CommandSyntaxChecker::PARAMS_OPTIONAL | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& format, absl::optional max_length) { + [](absl::string_view format, absl::optional max_length) { return FilterStateFormatter::create(format, max_length, true); }}}, {"DOWNSTREAM_PEER_CERT_V_START", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique(format); }}}, {"DOWNSTREAM_PEER_CERT_V_END", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique(format); }}}, {"UPSTREAM_PEER_CERT_V_START", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique(format); }}}, {"UPSTREAM_PEER_CERT_V_END", {CommandSyntaxChecker::PARAMS_OPTIONAL, - [](const std::string& format, absl::optional) { + [](absl::string_view format, absl::optional) { return std::make_unique(format); }}}, {"ENVIRONMENT", {CommandSyntaxChecker::PARAMS_REQUIRED | CommandSyntaxChecker::LENGTH_ALLOWED, - [](const std::string& key, absl::optional max_length) { + [](absl::string_view key, absl::optional max_length) { return std::make_unique(key, max_length); }}}, {"UPSTREAM_CONNECTION_POOL_READY_DURATION", {CommandSyntaxChecker::COMMAND_ONLY, - [](const std::string&, const absl::optional&) { + [](absl::string_view, const absl::optional&) { return std::make_unique( [](const StreamInfo::StreamInfo& stream_info) -> absl::optional { @@ -1784,8 +1805,8 @@ class BuiltInStreamInfoCommandParser : public StreamInfoCommandParser { BuiltInStreamInfoCommandParser() = default; // StreamInfoCommandParser - StreamInfoFormatterProviderPtr parse(const std::string& command, const std::string& sub_command, - absl::optional& max_length) const override { + StreamInfoFormatterProviderPtr parse(absl::string_view command, absl::string_view sub_command, + absl::optional max_length) const override { auto it = getKnownStreamInfoFormatterProviders().find(command); diff --git a/source/common/formatter/stream_info_formatter.h b/source/common/formatter/stream_info_formatter.h index 8de144eb0d4f..0cc80e0d911c 100644 --- a/source/common/formatter/stream_info_formatter.h +++ b/source/common/formatter/stream_info_formatter.h @@ -20,7 +20,7 @@ namespace Envoy { namespace Formatter { using StreamInfoFormatterProviderCreateFunc = - std::function)>; + std::function)>; enum class DurationPrecision { Milliseconds, Microseconds, Nanoseconds }; @@ -33,7 +33,7 @@ class MetadataFormatter : public StreamInfoFormatterProvider { public: using GetMetadataFunction = std::function; - MetadataFormatter(const std::string& filter_namespace, const std::vector& path, + MetadataFormatter(absl::string_view filter_namespace, const std::vector& path, absl::optional max_length, GetMetadataFunction get); // StreamInfoFormatterProvider @@ -57,8 +57,9 @@ class MetadataFormatter : public StreamInfoFormatterProvider { */ class DynamicMetadataFormatter : public MetadataFormatter { public: - DynamicMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, absl::optional max_length); + DynamicMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, + absl::optional max_length); }; /** @@ -66,8 +67,9 @@ class DynamicMetadataFormatter : public MetadataFormatter { */ class ClusterMetadataFormatter : public MetadataFormatter { public: - ClusterMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, absl::optional max_length); + ClusterMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, + absl::optional max_length); }; /** @@ -75,8 +77,8 @@ class ClusterMetadataFormatter : public MetadataFormatter { */ class UpstreamHostMetadataFormatter : public MetadataFormatter { public: - UpstreamHostMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, + UpstreamHostMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length); }; @@ -88,11 +90,11 @@ enum class FilterStateFormat { String, Proto, Field }; class FilterStateFormatter : public StreamInfoFormatterProvider { public: static std::unique_ptr - create(const std::string& format, const absl::optional& max_length, bool is_upstream); + create(absl::string_view format, absl::optional max_length, bool is_upstream); - FilterStateFormatter(const std::string& key, absl::optional max_length, + FilterStateFormatter(absl::string_view key, absl::optional max_length, bool serialize_as_string, bool is_upstream = false, - const std::string& field_name = ""); + absl::string_view field_name = {}); // StreamInfoFormatterProvider absl::optional format(const StreamInfo::StreamInfo&) const override; @@ -169,7 +171,7 @@ class SystemTimeFormatter : public StreamInfoFormatterProvider { std::function(const StreamInfo::StreamInfo& stream_info)>; using TimeFieldExtractorPtr = std::unique_ptr; - SystemTimeFormatter(const std::string& format, TimeFieldExtractorPtr f, bool local_time = false); + SystemTimeFormatter(absl::string_view format, TimeFieldExtractorPtr f, bool local_time = false); // StreamInfoFormatterProvider absl::optional format(const StreamInfo::StreamInfo&) const override; @@ -187,7 +189,7 @@ class SystemTimeFormatter : public StreamInfoFormatterProvider { */ class StartTimeFormatter : public SystemTimeFormatter { public: - StartTimeFormatter(const std::string& format); + StartTimeFormatter(absl::string_view format); }; /** @@ -196,7 +198,7 @@ class StartTimeFormatter : public SystemTimeFormatter { */ class DownstreamPeerCertVStartFormatter : public SystemTimeFormatter { public: - DownstreamPeerCertVStartFormatter(const std::string& format); + DownstreamPeerCertVStartFormatter(absl::string_view format); }; /** @@ -205,7 +207,7 @@ class DownstreamPeerCertVStartFormatter : public SystemTimeFormatter { */ class DownstreamPeerCertVEndFormatter : public SystemTimeFormatter { public: - DownstreamPeerCertVEndFormatter(const std::string& format); + DownstreamPeerCertVEndFormatter(absl::string_view format); }; /** @@ -214,7 +216,7 @@ class DownstreamPeerCertVEndFormatter : public SystemTimeFormatter { */ class UpstreamPeerCertVStartFormatter : public SystemTimeFormatter { public: - UpstreamPeerCertVStartFormatter(const std::string& format); + UpstreamPeerCertVStartFormatter(absl::string_view format); }; /** @@ -223,7 +225,7 @@ class UpstreamPeerCertVStartFormatter : public SystemTimeFormatter { */ class UpstreamPeerCertVEndFormatter : public SystemTimeFormatter { public: - UpstreamPeerCertVEndFormatter(const std::string& format); + UpstreamPeerCertVEndFormatter(absl::string_view format); }; /** @@ -231,7 +233,7 @@ class UpstreamPeerCertVEndFormatter : public SystemTimeFormatter { */ class EnvironmentFormatter : public StreamInfoFormatterProvider { public: - EnvironmentFormatter(const std::string& key, absl::optional max_length); + EnvironmentFormatter(absl::string_view key, absl::optional max_length); // StreamInfoFormatterProvider absl::optional format(const StreamInfo::StreamInfo&) const override; diff --git a/source/common/formatter/substitution_format_utility.cc b/source/common/formatter/substitution_format_utility.cc index 1ec0b15cae98..919783fa997c 100644 --- a/source/common/formatter/substitution_format_utility.cc +++ b/source/common/formatter/substitution_format_utility.cc @@ -14,10 +14,10 @@ namespace Formatter { static const std::string DefaultUnspecifiedValueString = "-"; -absl::Status CommandSyntaxChecker::verifySyntax(CommandSyntaxFlags flags, - const std::string& command, - const std::string& subcommand, - const absl::optional& length) { +absl::Status CommandSyntaxChecker::verifySyntax(CommandSyntaxChecker::CommandSyntaxFlags flags, + absl::string_view command, + absl::string_view subcommand, + absl::optional length) { if ((flags == COMMAND_ONLY) && ((subcommand.length() != 0) || length.has_value())) { return absl::InvalidArgumentError( fmt::format("{} does not take any parameters or length", command)); @@ -92,12 +92,11 @@ absl::string_view SubstitutionFormatUtils::truncateStringView(absl::string_view return str.substr(0, max_length.value()); } -absl::Status SubstitutionFormatUtils::parseSubcommandHeaders(const std::string& subcommand, - std::string& main_header, - std::string& alternative_header) { +absl::StatusOr +SubstitutionFormatUtils::parseSubcommandHeaders(absl::string_view subcommand) { + absl::string_view main_header, alternative_header; // subs is used only to check if there are more than 2 headers separated by '?'. - std::vector subs; - alternative_header = ""; + std::vector subs; parseSubcommand(subcommand, '?', main_header, alternative_header, subs); if (!subs.empty()) { return absl::InvalidArgumentError( @@ -120,7 +119,7 @@ absl::Status SubstitutionFormatUtils::parseSubcommandHeaders(const std::string& "Invalid header configuration. Format string contains null or newline."); } } - return absl::OkStatus(); + return {std::make_pair(main_header, alternative_header)}; } } // namespace Formatter diff --git a/source/common/formatter/substitution_format_utility.h b/source/common/formatter/substitution_format_utility.h index b1176f4d0760..56a17e1cc56b 100644 --- a/source/common/formatter/substitution_format_utility.h +++ b/source/common/formatter/substitution_format_utility.h @@ -24,8 +24,8 @@ class CommandSyntaxChecker { static constexpr CommandSyntaxFlags LENGTH_ALLOWED = 1 << 2; static absl::Status verifySyntax(CommandSyntaxChecker::CommandSyntaxFlags flags, - const std::string& command, const std::string& subcommand, - const absl::optional& length); + absl::string_view command, absl::string_view subcommand, + absl::optional length); }; /** @@ -66,9 +66,8 @@ class SubstitutionFormatUtils { * See doc: * https://envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/access_log#format-rules */ - static absl::Status parseSubcommandHeaders(const std::string& subcommand, - std::string& main_header, - std::string& alternative_header); + using HeaderPair = std::pair; + static absl::StatusOr parseSubcommandHeaders(absl::string_view subcommand); /* Variadic function template to parse the subcommand and assign found tokens to sequence of params. @@ -85,24 +84,23 @@ class SubstitutionFormatUtils { untouched. */ template - static void parseSubcommand(const std::string& subcommand, const char separator, + static void parseSubcommand(absl::string_view subcommand, const char separator, Tokens&&... params) { - std::vector tokens; - tokens = absl::StrSplit(subcommand, separator); + std::vector tokens = absl::StrSplit(subcommand, separator); std::vector::iterator it = tokens.begin(); ( [&](auto& param) { if (it != tokens.end()) { if constexpr (std::is_same_v::type, - std::string>) { - // Compile time handler for std::string. - param = std::string(*it); + absl::string_view>) { + // Compile time handler for absl::string_view. + param = *it; it++; } else { // Compile time handler for container type. It will catch all remaining tokens and // move iterator to the end. do { - param.push_back(std::string(*it)); + param.push_back(*it); it++; } while (it != tokens.end()); } diff --git a/source/common/formatter/substitution_formatter.cc b/source/common/formatter/substitution_formatter.cc index 5a71a9b48ece..a3278cf5d71b 100644 --- a/source/common/formatter/substitution_formatter.cc +++ b/source/common/formatter/substitution_formatter.cc @@ -3,7 +3,7 @@ namespace Envoy { namespace Formatter { -const std::regex& SubstitutionFormatParser::commandWithArgsRegex() { +const re2::RE2& SubstitutionFormatParser::commandWithArgsRegex() { // The following regex is used to check validity of the formatter command and to // extract groups. // The formatter command has the following format: @@ -35,20 +35,20 @@ const std::regex& SubstitutionFormatParser::commandWithArgsRegex() { // Group is used only to specify allowed characters. | | // | | | // | | | - // _________________ _______________ _____________ - // | | | | | | - CONSTRUCT_ON_FIRST_USE(std::regex, + // _________________ _____________ _____________ + // | | | | | | + CONSTRUCT_ON_FIRST_USE(re2::RE2, R"EOF(^%((?:[A-Z]|[0-9]|_)+)(?:\((.*?)\))?(?::([0-9]+))?%)EOF"); - // |__________________| |______| |______| - // | | | - // Capturing group specifying COMMAND -- | | - // The index of this group is 1. | | - // | | - // Capturing group for SUBCOMMAND. If present, it will ----- | - // contain SUBCOMMAND without "(" and ")". The index | - // of SUBCOMMAND group is 2. | - // | - // Capturing group for LENGTH. If present, it will ------------------------- + // |__________________| |___| |______| + // | | | + // Capturing group specifying COMMAND --- | | + // The index of this group is 1. | | + // | | + // Capturing group for SUBCOMMAND. If present, it will --- | + // contain SUBCOMMAND without "(" and ")". The index | + // of SUBCOMMAND group is 2. | + // | + // Capturing group for LENGTH. If present, it will ---------------------- // contain just number without ":". The index of // LENGTH group is 3. // clang-format on diff --git a/source/common/formatter/substitution_formatter.h b/source/common/formatter/substitution_formatter.h index 8353ff19c37d..abf6ff5a69c7 100644 --- a/source/common/formatter/substitution_formatter.h +++ b/source/common/formatter/substitution_formatter.h @@ -17,6 +17,7 @@ #include "source/common/json/json_loader.h" #include "absl/types/optional.h" +#include "re2/re2.h" namespace Envoy { namespace Formatter { @@ -28,7 +29,7 @@ namespace Formatter { template class PlainStringFormatterBase : public FormatterProviderBase { public: - PlainStringFormatterBase(const std::string& str) { str_.set_string_value(str); } + PlainStringFormatterBase(absl::string_view str) { str_.set_string_value(str); } // FormatterProviderBase absl::optional formatWithContext(const FormatterContext&, @@ -102,19 +103,21 @@ class SubstitutionFormatParser { parse(absl::string_view format, const std::vector>& command_parsers = {}) { std::string current_token; + current_token.reserve(32); std::vector> formatters; - for (size_t pos = 0; pos < format.size(); ++pos) { + for (size_t pos = 0; pos < format.size();) { if (format[pos] != '%') { - current_token += format[pos]; + current_token.push_back(format[pos]); + pos++; continue; } // escape '%%' if (format.size() > pos + 1) { if (format[pos + 1] == '%') { - current_token += '%'; - pos++; + current_token.push_back('%'); + pos += 2; continue; } } @@ -122,35 +125,22 @@ class SubstitutionFormatParser { if (!current_token.empty()) { formatters.emplace_back(FormatterProviderBasePtr{ new PlainStringFormatterBase(current_token)}); - current_token = ""; + current_token.clear(); } - std::smatch m; - const std::string search_space = std::string(format.substr(pos)); - if (!std::regex_search(search_space, m, commandWithArgsRegex())) { + absl::string_view sub_format = format.substr(pos); + const size_t sub_format_size = sub_format.size(); + + absl::string_view command, command_arg; + absl::optional max_len; + + if (!re2::RE2::Consume(&sub_format, commandWithArgsRegex(), &command, &command_arg, + &max_len)) { throwEnvoyExceptionOrPanic( fmt::format("Incorrect configuration: {}. Couldn't find valid command at position {}", format, pos)); } - const std::string match = m.str(0); - // command is at at index 1. - const std::string command = m.str(1); - // subcommand is at index 2. - const std::string subcommand = m.str(2); - // optional length is at index 3. If present, validate that it is valid integer. - absl::optional max_length; - if (m.str(3).length() != 0) { - size_t length_value; - if (!absl::SimpleAtoi(m.str(3), &length_value)) { - throwEnvoyExceptionOrPanic(absl::StrCat("Length must be an integer, given: ", m.str(3))); - } - max_length = length_value; - } - std::vector path; - - const size_t command_end_position = pos + m.str(0).length() - 1; - bool added = false; // The order of the following parsers is because the historical behavior. And we keep it @@ -159,7 +149,7 @@ class SubstitutionFormatParser { // First, try the built-in command parsers. for (const auto& cmd : BuiltInCommandParserFactoryHelper::commandParsers()) { - auto formatter = cmd->parse(command, subcommand, max_length); + auto formatter = cmd->parse(command, command_arg, max_len); if (formatter) { formatters.push_back(std::move(formatter)); added = true; @@ -170,7 +160,7 @@ class SubstitutionFormatParser { // Next, try the command parsers provided by the user. if (!added) { for (const auto& cmd : command_parsers) { - auto formatter = cmd->parse(command, subcommand, max_length); + auto formatter = cmd->parse(command, command_arg, max_len); if (formatter) { formatters.push_back(std::move(formatter)); added = true; @@ -182,7 +172,7 @@ class SubstitutionFormatParser { // Finally, try the command parsers that are built-in and context-independent. if (!added) { for (const auto& cmd : BuiltInStreamInfoCommandParserFactoryHelper::commandParsers()) { - auto formatter = cmd->parse(command, subcommand, max_length); + auto formatter = cmd->parse(command, command_arg, max_len); if (formatter) { formatters.push_back(std::make_unique>( std::move(formatter))); @@ -196,7 +186,7 @@ class SubstitutionFormatParser { throwEnvoyExceptionOrPanic(fmt::format("Not supported field in StreamInfo: {}", command)); } - pos = command_end_position; + pos += (sub_format_size - sub_format.size()); } if (!current_token.empty() || format.empty()) { @@ -210,7 +200,7 @@ class SubstitutionFormatParser { } private: - static const std::regex& commandWithArgsRegex(); + static const re2::RE2& commandWithArgsRegex(); }; inline constexpr absl::string_view DefaultUnspecifiedValueStringView = "-"; diff --git a/source/common/grpc/async_client_impl.h b/source/common/grpc/async_client_impl.h index b1788812a0e9..aa4fb580455b 100644 --- a/source/common/grpc/async_client_impl.h +++ b/source/common/grpc/async_client_impl.h @@ -87,6 +87,7 @@ class AsyncStreamImpl : public RawAsyncStream, bool hasResetStream() const { return http_reset_; } const StreamInfo::StreamInfo& streamInfo() const override { return stream_->streamInfo(); } + StreamInfo::StreamInfo& streamInfo() override { return stream_->streamInfo(); } void setWatermarkCallbacks(Http::SidestreamWatermarkCallbacks& callbacks) override { stream_->setWatermarkCallbacks(callbacks); diff --git a/source/common/grpc/async_client_manager_impl.cc b/source/common/grpc/async_client_manager_impl.cc index 9d3bf65d132c..aabd46907636 100644 --- a/source/common/grpc/async_client_manager_impl.cc +++ b/source/common/grpc/async_client_manager_impl.cc @@ -167,7 +167,7 @@ absl::StatusOr AsyncClientManagerImpl::getOrCreateRawAs } auto factory_or_error = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); client = factory_or_error.value()->createUncachedRawAsyncClient(); raw_async_client_cache_->setCache(config_with_hash_key, client); return client; @@ -183,7 +183,7 @@ AsyncClientManagerImpl::getOrCreateRawAsyncClientWithHashKey( } auto factory_or_error = factoryForGrpcService(config_with_hash_key.config(), scope, skip_cluster_check); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); client = factory_or_error.value()->createUncachedRawAsyncClient(); raw_async_client_cache_->setCache(config_with_hash_key, client); return client; diff --git a/source/common/grpc/google_async_client_impl.h b/source/common/grpc/google_async_client_impl.h index 23bb2b6fbfdf..9ee8bdc28b30 100644 --- a/source/common/grpc/google_async_client_impl.h +++ b/source/common/grpc/google_async_client_impl.h @@ -236,6 +236,7 @@ class GoogleAsyncStreamImpl : public RawAsyncStream, return bytes_in_write_pending_queue_ > parent_.perStreamBufferLimitBytes(); } const StreamInfo::StreamInfo& streamInfo() const override { return unused_stream_info_; } + StreamInfo::StreamInfo& streamInfo() override { return unused_stream_info_; } // Google-gRPC code doesn't use Envoy watermark buffers, so the functions below are not used. void setWatermarkCallbacks(Http::SidestreamWatermarkCallbacks&) override {} diff --git a/source/common/grpc/typed_async_client.h b/source/common/grpc/typed_async_client.h index 294cb98de3e4..c4ed83f74bf5 100644 --- a/source/common/grpc/typed_async_client.h +++ b/source/common/grpc/typed_async_client.h @@ -58,6 +58,7 @@ template class AsyncStream /* : public RawAsyncStream */ { bool operator==(RawAsyncStream* stream) const { return stream_ == stream; } bool operator!=(RawAsyncStream* stream) const { return stream_ != stream; } const StreamInfo::StreamInfo& streamInfo() const { return stream_->streamInfo(); } + StreamInfo::StreamInfo& streamInfo() { return stream_->streamInfo(); } private: RawAsyncStream* stream_{}; diff --git a/source/common/http/async_client_impl.cc b/source/common/http/async_client_impl.cc index a0bec05e0d5a..493beb35c9a7 100644 --- a/source/common/http/async_client_impl.cc +++ b/source/common/http/async_client_impl.cc @@ -133,6 +133,10 @@ AsyncStreamImpl::AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCal stream_info_.setUpstreamClusterInfo(parent_.cluster_); stream_info_.route_ = route_; + if (options.parent_context.stream_info != nullptr) { + stream_info_.setParentStreamInfo(*options.parent_context.stream_info); + } + if (options.buffer_body_for_retry) { buffered_body_ = std::make_unique(account_); } diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 91214a81a605..efbceb7e93d7 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -150,6 +150,7 @@ class AsyncStreamImpl : public virtual AsyncClient::Stream, void reset() override; bool isAboveWriteBufferHighWatermark() const override { return high_watermark_calls_ > 0; } const StreamInfo::StreamInfo& streamInfo() const override { return stream_info_; } + StreamInfo::StreamInfoImpl& streamInfo() override { return stream_info_; } protected: AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCallbacks& callbacks, @@ -157,7 +158,6 @@ class AsyncStreamImpl : public virtual AsyncClient::Stream, bool remoteClosed() { return remote_closed_; } void closeLocal(bool end_stream); - StreamInfo::StreamInfoImpl& streamInfo() override { return stream_info_; } AsyncClientImpl& parent_; // Callback to listen for stream destruction. diff --git a/source/common/http/conn_manager_config.h b/source/common/http/conn_manager_config.h index a02a45ddc988..7a2b300b839f 100644 --- a/source/common/http/conn_manager_config.h +++ b/source/common/http/conn_manager_config.h @@ -83,6 +83,7 @@ namespace Http { GAUGE(downstream_cx_ssl_active, Accumulate) \ GAUGE(downstream_cx_tx_bytes_buffered, Accumulate) \ GAUGE(downstream_cx_upgrades_active, Accumulate) \ + GAUGE(downstream_cx_http1_soft_drain, Accumulate) \ GAUGE(downstream_rq_active, Accumulate) \ HISTOGRAM(downstream_cx_length_ms, Milliseconds) \ HISTOGRAM(downstream_rq_time, Milliseconds) @@ -290,6 +291,12 @@ class ConnectionManagerConfig { */ virtual absl::optional maxConnectionDuration() const PURE; + /** + * @return whether maxConnectionDuration allows HTTP1 clients to choose when to close connection + * (rather than Envoy closing the connection itself when there are no active streams). + */ + virtual bool http1SafeMaxConnectionDuration() const PURE; + /** * @return maximum request headers size the connection manager will accept. */ diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 2b709f2eebd2..65a2b032ec4e 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -213,6 +213,10 @@ ConnectionManagerImpl::~ConnectionManagerImpl() { } } + if (soft_drain_http1_) { + stats_.named_.downstream_cx_http1_soft_drain_.dec(); + } + conn_length_->complete(); user_agent_.completeConnectionLength(*conn_length_); } @@ -243,7 +247,7 @@ void ConnectionManagerImpl::doEndStream(ActiveStream& stream, bool check_for_def // here is when Envoy "ends" the stream by calling recreateStream at which point recreateStream // explicitly nulls out response_encoder to avoid the downstream being notified of the // Envoy-internal stream instance being ended. - if (stream.response_encoder_ != nullptr && (!stream.filter_manager_.remoteDecodeComplete() || + if (stream.response_encoder_ != nullptr && (!stream.filter_manager_.decoderObservedEndStream() || !stream.state_.codec_saw_local_complete_)) { // Indicate local is complete at this point so that if we reset during a continuation, we don't // raise further data or trailers. @@ -280,17 +284,18 @@ void ConnectionManagerImpl::doEndStream(ActiveStream& stream, bool check_for_def drain_state_ = DrainState::Closing; } - // If HTTP/1.0 has no content length, it is framed by close and won't consider - // the request complete until the FIN is read. Don't delay close in this case. - bool http_10_sans_cl = (codec_->protocol() == Protocol::Http10) && - (!stream.response_headers_ || !stream.response_headers_->ContentLength()); - // We also don't delay-close in the case of HTTP/1.1 where the request is - // fully read, as there's no race condition to avoid. - const bool connection_close = - stream.filter_manager_.streamInfo().shouldDrainConnectionUponCompletion(); - bool request_complete = stream.filter_manager_.remoteDecodeComplete(); - if (check_for_deferred_close) { + // If HTTP/1.0 has no content length, it is framed by close and won't consider + // the request complete until the FIN is read. Don't delay close in this case. + const bool http_10_sans_cl = + (codec_->protocol() == Protocol::Http10) && + (!stream.response_headers_ || !stream.response_headers_->ContentLength()); + // We also don't delay-close in the case of HTTP/1.1 where the request is + // fully read, as there's no race condition to avoid. + const bool connection_close = + stream.filter_manager_.streamInfo().shouldDrainConnectionUponCompletion(); + const bool request_complete = stream.filter_manager_.decoderObservedEndStream(); + // Don't do delay close for HTTP/1.0 or if the request is complete. checkForDeferredClose(connection_close && (request_complete || http_10_sans_cl)); } @@ -412,6 +417,12 @@ RequestDecoder& ConnectionManagerImpl::newStream(ResponseEncoder& response_encod stats_.named_.downstream_cx_max_requests_reached_.inc(); } + if (soft_drain_http1_) { + new_stream->filter_manager_.streamInfo().setShouldDrainConnectionUponCompletion(true); + // Prevent erroneous debug log of closing due to incoming connection close header. + drain_state_ = DrainState::Closing; + } + new_stream->state_.is_internally_created_ = is_internally_created; new_stream->response_encoder_ = &response_encoder; new_stream->response_encoder_->getStream().addCallbacks(*new_stream); @@ -723,7 +734,15 @@ void ConnectionManagerImpl::onConnectionDurationTimeout() { StreamInfo::CoreResponseFlag::DurationTimeout, StreamInfo::ResponseCodeDetails::get().DurationTimeout); } else if (drain_state_ == DrainState::NotDraining) { - startDrainSequence(); + if (config_->http1SafeMaxConnectionDuration() && codec_->protocol() < Protocol::Http2) { + ENVOY_CONN_LOG(debug, + "HTTP1-safe max connection duration is configured -- skipping drain sequence.", + read_callbacks_->connection()); + stats_.named_.downstream_cx_http1_soft_drain_.inc(); + soft_drain_http1_ = true; + } else { + startDrainSequence(); + } } } @@ -924,21 +943,21 @@ void ConnectionManagerImpl::ActiveStream::onIdleTimeout() { connection_manager_.stats_.named_.downstream_rq_idle_timeout_.inc(); filter_manager_.streamInfo().setResponseFlag(StreamInfo::CoreResponseFlag::StreamIdleTimeout); - sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.remoteDecodeComplete()), + sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.decoderObservedEndStream()), "stream timeout", nullptr, absl::nullopt, StreamInfo::ResponseCodeDetails::get().StreamIdleTimeout); } void ConnectionManagerImpl::ActiveStream::onRequestTimeout() { connection_manager_.stats_.named_.downstream_rq_timeout_.inc(); - sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.remoteDecodeComplete()), + sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.decoderObservedEndStream()), "request timeout", nullptr, absl::nullopt, StreamInfo::ResponseCodeDetails::get().RequestOverallTimeout); } void ConnectionManagerImpl::ActiveStream::onRequestHeaderTimeout() { connection_manager_.stats_.named_.downstream_rq_header_timeout_.inc(); - sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.remoteDecodeComplete()), + sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.decoderObservedEndStream()), "request header timeout", nullptr, absl::nullopt, StreamInfo::ResponseCodeDetails::get().RequestHeaderTimeout); } @@ -946,7 +965,7 @@ void ConnectionManagerImpl::ActiveStream::onRequestHeaderTimeout() { void ConnectionManagerImpl::ActiveStream::onStreamMaxDurationReached() { ENVOY_STREAM_LOG(debug, "Stream max duration time reached", *this); connection_manager_.stats_.named_.downstream_rq_max_duration_reached_.inc(); - sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.remoteDecodeComplete()), + sendLocalReply(Http::Utility::maybeRequestTimeoutCode(filter_manager_.decoderObservedEndStream()), "downstream duration timeout", nullptr, Grpc::Status::WellKnownGrpcStatus::DeadlineExceeded, StreamInfo::ResponseCodeDetails::get().MaxDurationTimeout); @@ -1112,7 +1131,7 @@ bool ConnectionManagerImpl::ActiveStream::validateTrailers() { void ConnectionManagerImpl::ActiveStream::maybeEndDecode(bool end_stream) { // If recreateStream is called, the HCM rewinds state and may send more encodeData calls. - if (end_stream && !filter_manager_.remoteDecodeComplete()) { + if (end_stream && !filter_manager_.decoderObservedEndStream()) { filter_manager_.streamInfo().downstreamTiming().onLastDownstreamRxByteReceived( connection_manager_.dispatcher_->timeSource()); ENVOY_STREAM_LOG(debug, "request end stream", *this); @@ -1135,7 +1154,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapSharedPt *headers); // We only want to record this when reading the headers the first time, not when recreating // a stream. - if (!filter_manager_.remoteDecodeComplete()) { + if (!filter_manager_.decoderObservedEndStream()) { filter_manager_.streamInfo().downstreamTiming().onLastDownstreamHeaderRxByteReceived( connection_manager_.dispatcher_->timeSource()); } @@ -1151,17 +1170,11 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapSharedPt // Both shouldDrainConnectionUponCompletion() and is_head_request_ affect local replies: set them // as early as possible. const Protocol protocol = connection_manager_.codec_->protocol(); - if (Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.http1_connection_close_header_in_redirect")) { - if (HeaderUtility::shouldCloseConnection(protocol, *request_headers_)) { - // Only mark the connection to be closed if the request indicates so. The connection might - // already be marked so before this step, in which case if shouldCloseConnection() returns - // false, the stream info value shouldn't be overridden. - filter_manager_.streamInfo().setShouldDrainConnectionUponCompletion(true); - } - } else { - filter_manager_.streamInfo().setShouldDrainConnectionUponCompletion( - HeaderUtility::shouldCloseConnection(protocol, *request_headers_)); + if (HeaderUtility::shouldCloseConnection(protocol, *request_headers_)) { + // Only mark the connection to be closed if the request indicates so. The connection might + // already be marked so before this step, in which case if shouldCloseConnection() returns + // false, the stream info value shouldn't be overridden. + filter_manager_.streamInfo().setShouldDrainConnectionUponCompletion(true); } filter_manager_.streamInfo().protocol(protocol); @@ -1763,7 +1776,7 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ResponseHeaderMap& heade // If we are destroying a stream before remote is complete and the connection does not support // multiplexing, we should disconnect since we don't want to wait around for the request to // finish. - if (!filter_manager_.remoteDecodeComplete()) { + if (!filter_manager_.decoderObservedEndStream()) { if (connection_manager_.codec_->protocol() < Protocol::Http2) { connection_manager_.drain_state_ = DrainState::Closing; } diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index a325dff0dfb2..34c96fab02f1 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -606,6 +606,8 @@ class ConnectionManagerImpl : Logger::Loggable, // A connection duration timer. Armed during handling new connection if enabled in config. Event::TimerPtr connection_duration_timer_; Event::TimerPtr drain_timer_; + // When set to true, add Connection:close response header to nudge downstream client to reconnect. + bool soft_drain_http1_{false}; Random::RandomGenerator& random_generator_; Runtime::Loader& runtime_; const LocalInfo::LocalInfo& local_info_; diff --git a/source/common/http/conn_pool_grid.cc b/source/common/http/conn_pool_grid.cc index 8605f2dbc9c2..21dfc6a0927b 100644 --- a/source/common/http/conn_pool_grid.cc +++ b/source/common/http/conn_pool_grid.cc @@ -26,12 +26,19 @@ absl::string_view describePool(const ConnectionPool::Instance& pool) { static constexpr uint32_t kDefaultTimeoutMs = 300; -std::string getSni(const Network::TransportSocketOptionsConstSharedPtr& options, - Network::UpstreamTransportSocketFactory& transport_socket_factory) { +std::string getTargetHostname(const Network::TransportSocketOptionsConstSharedPtr& options, + Upstream::HostConstSharedPtr& host) { if (options && options->serverNameOverride().has_value()) { return options->serverNameOverride().value(); } - return std::string(transport_socket_factory.defaultServerNameIndication()); + std::string default_sni = + std::string(host->transportSocketFactory().defaultServerNameIndication()); + if (!default_sni.empty() || + !Runtime::runtimeFeatureEnabled("envoy.reloadable_features.allow_alt_svc_for_ips")) { + return default_sni; + } + // If there's no configured SNI the hostname is probably an IP address. Return it here. + return host->hostname(); } } // namespace @@ -297,7 +304,7 @@ ConnectivityGrid::ConnectivityGrid( time_source_(time_source), alternate_protocols_(alternate_protocols), quic_stat_names_(quic_stat_names), scope_(scope), // TODO(RyanTheOptimist): Figure out how scheme gets plumbed in here. - origin_("https", getSni(transport_socket_options, host_->transportSocketFactory()), + origin_("https", getTargetHostname(transport_socket_options, host_), host_->address()->ip()->port()), quic_info_(quic_info), priority_(priority) { // ProdClusterManagerFactory::allocateConnPool verifies the protocols are HTTP/1, HTTP/2 and diff --git a/source/common/http/filter_chain_helper.cc b/source/common/http/filter_chain_helper.cc index 4963dd6e3ae0..05ad8023d440 100644 --- a/source/common/http/filter_chain_helper.cc +++ b/source/common/http/filter_chain_helper.cc @@ -27,9 +27,7 @@ void FilterChainUtility::createFilterChainForFactories( auto config = filter_config_provider.provider->config(); if (config.has_value()) { - Filter::NamedHttpFilterFactoryCb& factory_cb = config.value().get(); - manager.applyFilterFactoryCb({filter_config_provider.provider->name(), factory_cb.name}, - factory_cb.factory_cb); + manager.applyFilterFactoryCb({filter_config_provider.provider->name()}, config.ref()); continue; } diff --git a/source/common/http/filter_chain_helper.h b/source/common/http/filter_chain_helper.h index 7b8df370b0d6..24d0cda93c87 100644 --- a/source/common/http/filter_chain_helper.h +++ b/source/common/http/filter_chain_helper.h @@ -16,10 +16,10 @@ namespace Envoy { namespace Http { using DownstreamFilterConfigProviderManager = - Filter::FilterConfigProviderManager; using UpstreamFilterConfigProviderManager = - Filter::FilterConfigProviderManager; // Allows graceful handling of missing configuration for ECDS. @@ -42,7 +42,7 @@ static Http::FilterFactoryCb MissingConfigFilterFactory = class FilterChainUtility : Logger::Loggable { public: struct FilterFactoryProvider { - Filter::FilterConfigProviderPtr provider; + Filter::FilterConfigProviderPtr provider; // If true, this filter is disabled by default and must be explicitly enabled by // route configuration. bool disabled{}; @@ -70,7 +70,7 @@ class FilterChainHelper : Logger::Loggable { public: using FilterFactoriesList = FilterChainUtility::FilterFactoriesList; using FilterConfigProviderManager = - Filter::FilterConfigProviderManager; + Filter::FilterConfigProviderManager; FilterChainHelper(FilterConfigProviderManager& filter_config_provider_manager, Server::Configuration::ServerFactoryContext& server_context, @@ -146,14 +146,13 @@ class FilterChainHelper : Logger::Loggable { if (!callback_or_error.status().ok()) { return callback_or_error.status(); } - Http::FilterFactoryCb callback = callback_or_error.value(); dependency_manager.registerFilter(factory->name(), *factory->dependencies()); const bool is_terminal = factory->isTerminalFilterByProto(*message, server_context_); RETURN_IF_NOT_OK(Config::Utility::validateTerminalFilters(proto_config.name(), factory->name(), filter_chain_type, is_terminal, last_filter_in_current_config)); auto filter_config_provider = filter_config_provider_manager_.createStaticFilterConfigProvider( - {factory->name(), callback}, proto_config.name()); + callback_or_error.value(), proto_config.name()); #ifdef ENVOY_ENABLE_YAML ENVOY_LOG(debug, " name: {}", filter_config_provider->name()); ENVOY_LOG(debug, " config: {}", diff --git a/source/common/http/filter_manager.cc b/source/common/http/filter_manager.cc index b2ab8f0d4c83..d499e03483eb 100644 --- a/source/common/http/filter_manager.cc +++ b/source/common/http/filter_manager.cc @@ -91,7 +91,7 @@ void ActiveStreamFilterBase::commonContinue() { // future. if (!headers_continued_) { headers_continued_ = true; - doHeaders(complete() && !bufferedData() && !hasTrailers()); + doHeaders(observedEndStream() && !bufferedData() && !hasTrailers()); } doMetadata(); @@ -102,7 +102,7 @@ void ActiveStreamFilterBase::commonContinue() { // on doData() to do so. const bool had_trailers_before_data = hasTrailers(); if (bufferedData()) { - doData(complete() && !had_trailers_before_data); + doData(observedEndStream() && !had_trailers_before_data); } if (had_trailers_before_data) { @@ -197,7 +197,7 @@ bool ActiveStreamFilterBase::commonHandleAfterDataCallback(FilterDataStatus stat status == FilterDataStatus::StopIterationAndWatermark) { buffer_was_streaming = status == FilterDataStatus::StopIterationAndWatermark; commonHandleBufferData(provided_data); - } else if (complete() && !hasTrailers() && !bufferedData() && + } else if (observedEndStream() && !hasTrailers() && !bufferedData() && // If the stream is destroyed, no need to handle the data buffer or trailers. // This can occur if the filter calls sendLocalReply. !parent_.state_.destroyed_) { @@ -347,13 +347,13 @@ bool ActiveStreamDecoderFilter::canContinue() { // continue to further filters. A concrete example of this is a filter buffering data, the // last data frame comes in and the filter continues, but the final buffering takes the stream // over the high watermark such that a 413 is returned. - return !parent_.state_.local_complete_; + return !parent_.stopDecoderFilterChain(); } bool ActiveStreamEncoderFilter::canContinue() { // As with ActiveStreamDecoderFilter::canContinue() make sure we do not // continue if a local reply has been sent. - return !parent_.state_.remote_encode_complete_; + return !parent_.state_.encoder_filter_chain_complete_; } Buffer::InstancePtr ActiveStreamDecoderFilter::createBuffer() { @@ -369,7 +369,7 @@ Buffer::InstancePtr& ActiveStreamDecoderFilter::bufferedData() { return parent_.buffered_request_data_; } -bool ActiveStreamDecoderFilter::complete() { return parent_.remoteDecodeComplete(); } +bool ActiveStreamDecoderFilter::observedEndStream() { return parent_.decoderObservedEndStream(); } void ActiveStreamDecoderFilter::doHeaders(bool end_stream) { parent_.decodeHeaders(this, *parent_.filter_manager_callbacks_.requestHeaders(), end_stream); @@ -557,7 +557,7 @@ void FilterManager::decodeHeaders(ActiveStreamDecoderFilter* filter, RequestHead (*entry)->processed_headers_ = true; const auto continue_iteration = (*entry)->commonHandleAfterHeadersCallback(status, end_stream); - ENVOY_BUG(!continue_iteration || !state_.local_complete_, + ENVOY_BUG(!continue_iteration || !stopDecoderFilterChain(), fmt::format( "filter={} did not return StopAll or StopIteration after sending a local reply.", (*entry)->filter_context_.config_name)); @@ -568,7 +568,7 @@ void FilterManager::decodeHeaders(ActiveStreamDecoderFilter* filter, RequestHead } // Skip processing metadata after sending local reply - if (state_.local_complete_ && std::next(entry) != decoder_filters_.end()) { + if (stopDecoderFilterChain() && std::next(entry) != decoder_filters_.end()) { maybeContinueDecoding(continue_data_entry); return; } @@ -616,7 +616,7 @@ void FilterManager::decodeData(ActiveStreamDecoderFilter* filter, Buffer::Instan // If a response is complete or a reset has been sent, filters do not care about further body // data. Just drop it. - if (state_.local_complete_) { + if (stopDecoderFilterChain()) { return; } @@ -755,8 +755,9 @@ void FilterManager::addDecodedData(ActiveStreamDecoderFilter& filter, Buffer::In MetadataMapVector& FilterManager::addDecodedMetadata() { return *getRequestMetadataMapVector(); } void FilterManager::decodeTrailers(ActiveStreamDecoderFilter* filter, RequestTrailerMap& trailers) { - // See decodeData() above for why we check local_complete_ here. - if (state_.local_complete_) { + // If a response is complete or a reset has been sent, filters do not care about further body + // data. Just drop it. + if (stopDecoderFilterChain()) { return; } @@ -858,13 +859,19 @@ FilterManager::commonEncodePrefix(ActiveStreamEncoderFilter* filter, bool end_st ENVOY_STREAM_LOG(trace, "commonEncodePrefix end_stream: {}, isHalfCloseEnabled: {}", *this, end_stream, filter_manager_callbacks_.isHalfCloseEnabled()); if (filter == nullptr) { - // half close is enabled in case tcp proxying is done with http1 encoder. In this case, we - // should not set the local_complete_ flag to true when end_stream is true. - // setting local_complete_ to true will cause any data sent in the upstream direction to be - // dropped. - if (end_stream && !filter_manager_callbacks_.isHalfCloseEnabled()) { - ASSERT(!state_.local_complete_); - state_.local_complete_ = true; + if (end_stream) { + ASSERT(!state_.observed_encode_end_stream_); + state_.observed_encode_end_stream_ = true; + + // When half close semantics are disabled, receiving end stream from the upstream causes + // decoder filter to stop, as neither filters nor upstream is interested in downstream data. + // half close is enabled in case tcp proxying is done with http1 encoder. In this case, we + // should not stop decoder filter chain when end_stream is true, as it will cause any data + // sent in the upstream direction to be + // dropped. + if (!filter_manager_callbacks_.isHalfCloseEnabled()) { + state_.decoder_filter_chain_aborted_ = true; + } } return encoder_filters_.begin(); } @@ -1439,8 +1446,8 @@ void FilterManager::encodeTrailers(ActiveStreamEncoderFilter* filter, void FilterManager::maybeEndEncode(bool end_stream) { if (end_stream) { - ASSERT(!state_.remote_encode_complete_); - state_.remote_encode_complete_ = true; + ASSERT(!state_.encoder_filter_chain_complete_); + state_.encoder_filter_chain_complete_ = true; filter_manager_callbacks_.endStream(); } } @@ -1579,7 +1586,7 @@ bool ActiveStreamDecoderFilter::recreateStream(const ResponseHeaderMap* headers) // Because the filter's and the HCM view of if the stream has a body and if // the stream is complete may differ, re-check bytesReceived() to make sure // there was no body from the HCM's point of view. - if (!complete()) { + if (!observedEndStream()) { return false; } @@ -1624,7 +1631,9 @@ Buffer::InstancePtr ActiveStreamEncoderFilter::createBuffer() { Buffer::InstancePtr& ActiveStreamEncoderFilter::bufferedData() { return parent_.buffered_response_data_; } -bool ActiveStreamEncoderFilter::complete() { return parent_.state_.local_complete_; } +bool ActiveStreamEncoderFilter::observedEndStream() { + return parent_.state_.observed_encode_end_stream_; +} bool ActiveStreamEncoderFilter::has1xxHeaders() { return parent_.state_.has_1xx_headers_ && !continued_1xx_headers_; } diff --git a/source/common/http/filter_manager.h b/source/common/http/filter_manager.h index ef774fc28638..392f0bdcd239 100644 --- a/source/common/http/filter_manager.h +++ b/source/common/http/filter_manager.h @@ -91,7 +91,7 @@ struct ActiveStreamFilterBase : public virtual StreamFilterCallbacks, virtual bool canContinue() PURE; virtual Buffer::InstancePtr createBuffer() PURE; virtual Buffer::InstancePtr& bufferedData() PURE; - virtual bool complete() PURE; + virtual bool observedEndStream() PURE; virtual bool has1xxHeaders() PURE; virtual void do1xxHeaders() PURE; virtual void doHeaders(bool end_stream) PURE; @@ -212,7 +212,7 @@ struct ActiveStreamDecoderFilter : public ActiveStreamFilterBase, bool canContinue() override; Buffer::InstancePtr createBuffer() override; Buffer::InstancePtr& bufferedData() override; - bool complete() override; + bool observedEndStream() override; bool has1xxHeaders() override { return false; } void do1xxHeaders() override { IS_ENVOY_BUG("unexpected 1xx headers"); } void doHeaders(bool end_stream) override; @@ -304,7 +304,7 @@ struct ActiveStreamEncoderFilter : public ActiveStreamFilterBase, bool canContinue() override; Buffer::InstancePtr createBuffer() override; Buffer::InstancePtr& bufferedData() override; - bool complete() override; + bool observedEndStream() override; bool has1xxHeaders() override; void do1xxHeaders() override; void doHeaders(bool end_stream) override; @@ -745,7 +745,7 @@ class FilterManager : public ScopeTrackedObject, * @param end_stream whether the request is header only. */ void decodeHeaders(RequestHeaderMap& headers, bool end_stream) { - state_.remote_decode_complete_ = end_stream; + state_.observed_decode_end_stream_ = end_stream; decodeHeaders(nullptr, headers, end_stream); } @@ -755,7 +755,7 @@ class FilterManager : public ScopeTrackedObject, * @param end_stream whether this data is the end of the request. */ void decodeData(Buffer::Instance& data, bool end_stream) { - state_.remote_decode_complete_ = end_stream; + state_.observed_decode_end_stream_ = end_stream; decodeData(nullptr, data, end_stream, FilterIterationStartState::CanStartFromCurrent); } @@ -764,7 +764,7 @@ class FilterManager : public ScopeTrackedObject, * @param trailers the trailers to decode. */ void decodeTrailers(RequestTrailerMap& trailers) { - state_.remote_decode_complete_ = true; + state_.observed_decode_end_stream_ = true; decodeTrailers(nullptr, trailers); } @@ -819,8 +819,12 @@ class FilterManager : public ScopeTrackedObject, /** * Marks local processing as complete. + * TODO(yanvlasov): deprecate and decommission this function. */ - void setLocalComplete() { state_.local_complete_ = true; } + void setLocalComplete() { + state_.observed_encode_end_stream_ = true; + state_.decoder_filter_chain_aborted_ = true; + } /** * Whether the filters have been destroyed. @@ -830,7 +834,7 @@ class FilterManager : public ScopeTrackedObject, /** * Whether remote processing has been marked as complete. */ - virtual bool remoteDecodeComplete() const { return state_.remote_decode_complete_; } + virtual bool decoderObservedEndStream() const { return state_.observed_decode_end_stream_; } /** * Instructs the FilterManager to not create a filter chain. This makes it possible to issue @@ -864,18 +868,27 @@ class FilterManager : public ScopeTrackedObject, protected: struct State { State() - : remote_decode_complete_(false), remote_encode_complete_(false), local_complete_(false), - has_1xx_headers_(false), created_filter_chain_(false), is_head_request_(false), - is_grpc_request_(false), non_100_response_headers_encoded_(false), - under_on_local_reply_(false), decoder_filter_chain_aborted_(false), - encoder_filter_chain_aborted_(false), saw_downstream_reset_(false) {} + : encoder_filter_chain_complete_(false), observed_decode_end_stream_(false), + observed_encode_end_stream_(false), has_1xx_headers_(false), created_filter_chain_(false), + is_head_request_(false), is_grpc_request_(false), + non_100_response_headers_encoded_(false), under_on_local_reply_(false), + decoder_filter_chain_aborted_(false), encoder_filter_chain_aborted_(false), + saw_downstream_reset_(false) {} uint32_t filter_call_state_{0}; - bool remote_decode_complete_ : 1; - bool remote_encode_complete_ : 1; - bool local_complete_ : 1; // This indicates that local is complete prior to filter processing. - // A filter can still stop the stream from being complete as seen - // by the codec. + // Set after encoder filter chain has completed iteration. Prevents further calls to encoder + // filters. + bool encoder_filter_chain_complete_ : 1; + + // Set `true` when the filter manager observes end stream on the decoder path (from downstream + // client) before iteration of the decoder filter chain begins. This flag is used for setting + // end_stream value when resuming decoder filter chain iteration. + bool observed_decode_end_stream_ : 1; + // Set `true` when the filter manager observes end stream on the encoder path (from upstream + // server or Envoy's local reply) before iteration of the encoder filter chain begins. This flag + // is used for setting end_stream value when resuming encoder filter chain iteration. + bool observed_encode_end_stream_ : 1; + // By default, we will assume there are no 1xx. If encode1xxHeaders // is ever called, this is set to true so commonContinue resumes processing the 1xx. bool has_1xx_headers_ : 1; @@ -1018,6 +1031,8 @@ class FilterManager : public ScopeTrackedObject, return request_metadata_map_vector_.get(); } + bool stopDecoderFilterChain() { return state_.decoder_filter_chain_aborted_; } + FilterManagerCallbacks& filter_manager_callbacks_; Event::Dispatcher& dispatcher_; // This is unset if there is no downstream connection, e.g. for health check or @@ -1142,7 +1157,7 @@ class DownstreamFilterManager : public FilterManager { * For the DownstreamFilterManager rely on external state, to handle the case * of internal redirects. */ - bool remoteDecodeComplete() const override { + bool decoderObservedEndStream() const override { return streamInfo().downstreamTiming() && streamInfo().downstreamTiming()->lastDownstreamRxByteReceived().has_value(); } diff --git a/source/common/http/header_utility.cc b/source/common/http/header_utility.cc index 9091f8696835..bf8dd0b8d323 100644 --- a/source/common/http/header_utility.cc +++ b/source/common/http/header_utility.cc @@ -235,7 +235,96 @@ bool HeaderUtility::headerNameContainsUnderscore(const absl::string_view header_ return header_name.find('_') != absl::string_view::npos; } +namespace { +// This function validates the authority header for both HTTP/1 and HTTP/2. +// Note the HTTP/1 spec allows "user-info@host:port" for the authority, whereas +// the HTTP/2 spec only allows "host:port". Thus, this function permits all the +// HTTP/2 valid characters (similar to oghttp2's implementation) and the "@" character. +// Once UHV is used, this function should be removed, and the HTTP/1 and HTTP/2 +// authority validations should be different. +bool check_authority_h1_h2(const absl::string_view header_value) { + static constexpr char ValidAuthorityChars[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, + 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, + 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, + 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */, + 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, + 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, + 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, + 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, + 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, + 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, + 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, + 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, + 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, + 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, + 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, + 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, + 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, + 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, + 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, + 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, + 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, + 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, + 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, + 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, + 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, + 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, + 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, + 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, + 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, + 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, + 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, + 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, + 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, + 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, + 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, + 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, + 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, + 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ + }; + + for (const uint8_t c : header_value) { + if (!ValidAuthorityChars[c]) { + return false; + } + } + return true; +} +} // namespace + bool HeaderUtility::authorityIsValid(const absl::string_view header_value) { + if (Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.internal_authority_header_validator")) { + return check_authority_h1_h2(header_value); + } + #ifdef ENVOY_NGHTTP2 if (!Runtime::runtimeFeatureEnabled( "envoy.reloadable_features.http2_validate_authority_with_quiche")) { diff --git a/source/common/http/http2/codec_impl.cc b/source/common/http/http2/codec_impl.cc index e856dcc7f00f..9171d60a8865 100644 --- a/source/common/http/http2/codec_impl.cc +++ b/source/common/http/http2/codec_impl.cc @@ -1799,7 +1799,7 @@ bool ConnectionImpl::Http2Visitor::SendDataFrame(Http2StreamId stream_id, bool ConnectionImpl::Http2Visitor::OnFrameHeader(Http2StreamId stream_id, size_t length, uint8_t type, uint8_t flags) { - ENVOY_CONN_LOG(debug, "Http2Visitor::OnFrameHeader({}, {}, {}, {})", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor::OnFrameHeader({}, {}, {}, {})", connection_->connection_, stream_id, length, int(type), int(flags)); if (type == OGHTTP2_CONTINUATION_FRAME_TYPE) { @@ -1843,7 +1843,7 @@ ConnectionImpl::Http2Visitor::OnHeaderForStream(Http2StreamId stream_id, } bool ConnectionImpl::Http2Visitor::OnEndHeadersForStream(Http2StreamId stream_id) { - ENVOY_CONN_LOG(debug, "Http2Visitor::OnEndHeadersForStream({})", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor::OnEndHeadersForStream({})", connection_->connection_, stream_id); Status status = connection_->onHeaders(stream_id, current_frame_.length, current_frame_.flags); return 0 == connection_->setAndCheckCodecCallbackStatus(std::move(status)); @@ -1851,12 +1851,12 @@ bool ConnectionImpl::Http2Visitor::OnEndHeadersForStream(Http2StreamId stream_id bool ConnectionImpl::Http2Visitor::OnBeginDataForStream(Http2StreamId stream_id, size_t payload_length) { - ENVOY_CONN_LOG(debug, "Http2Visitor::OnBeginDataForStream({}, {})", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor::OnBeginDataForStream({}, {})", connection_->connection_, stream_id, payload_length); remaining_data_payload_ = payload_length; padding_length_ = 0; if (remaining_data_payload_ == 0 && (current_frame_.flags & FLAG_END_STREAM) == 0) { - ENVOY_CONN_LOG(debug, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, stream_id); Status status = connection_->onBeginData(stream_id, current_frame_.length, current_frame_.flags, padding_length_); @@ -1873,13 +1873,13 @@ bool ConnectionImpl::Http2Visitor::OnDataPaddingLength(Http2StreamId stream_id, padding_length_ = padding_length; remaining_data_payload_ -= padding_length; if (remaining_data_payload_ == 0 && (current_frame_.flags & FLAG_END_STREAM) == 0) { - ENVOY_CONN_LOG(debug, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, stream_id); Status status = connection_->onBeginData(stream_id, current_frame_.length, current_frame_.flags, padding_length_); return 0 == connection_->setAndCheckCodecCallbackStatus(std::move(status)); } - ENVOY_CONN_LOG(debug, "Http2Visitor: remaining data payload: {}, end_stream: {}", + ENVOY_CONN_LOG(trace, "Http2Visitor: remaining data payload: {}, end_stream: {}", connection_->connection_, remaining_data_payload_, bool(current_frame_.flags & FLAG_END_STREAM)); return true; @@ -1892,24 +1892,24 @@ bool ConnectionImpl::Http2Visitor::OnDataForStream(Http2StreamId stream_id, remaining_data_payload_ -= data.size(); if (result == 0 && remaining_data_payload_ == 0 && (current_frame_.flags & FLAG_END_STREAM) == 0) { - ENVOY_CONN_LOG(debug, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, stream_id); Status status = connection_->onBeginData(stream_id, current_frame_.length, current_frame_.flags, padding_length_); return 0 == connection_->setAndCheckCodecCallbackStatus(std::move(status)); } - ENVOY_CONN_LOG(debug, "Http2Visitor: remaining data payload: {}, end_stream: {}", + ENVOY_CONN_LOG(trace, "Http2Visitor: remaining data payload: {}, end_stream: {}", connection_->connection_, remaining_data_payload_, bool(current_frame_.flags & FLAG_END_STREAM)); return result == 0; } bool ConnectionImpl::Http2Visitor::OnEndStream(Http2StreamId stream_id) { - ENVOY_CONN_LOG(debug, "Http2Visitor::OnEndStream({})", connection_->connection_, stream_id); + ENVOY_CONN_LOG(trace, "Http2Visitor::OnEndStream({})", connection_->connection_, stream_id); if (current_frame_.type == OGHTTP2_DATA_FRAME_TYPE) { // `onBeginData` is invoked here to ensure that the connection has successfully validated and // processed the entire DATA frame. - ENVOY_CONN_LOG(debug, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, + ENVOY_CONN_LOG(trace, "Http2Visitor dispatching DATA for stream {}", connection_->connection_, stream_id); Status status = connection_->onBeginData(stream_id, current_frame_.length, current_frame_.flags, padding_length_); @@ -1926,7 +1926,7 @@ bool ConnectionImpl::Http2Visitor::OnCloseStream(Http2StreamId stream_id, Http2ErrorCode error_code) { Status status = connection_->onStreamClose(stream_id, static_cast(error_code)); if (stream_close_listener_) { - ENVOY_CONN_LOG(debug, "Http2Visitor invoking stream close listener for {}", + ENVOY_CONN_LOG(trace, "Http2Visitor invoking stream close listener for {}", connection_->connection_, stream_id); stream_close_listener_(stream_id); } diff --git a/source/common/http/http_server_properties_cache_impl.cc b/source/common/http/http_server_properties_cache_impl.cc index b694cc512f66..1b6cc15ba6e1 100644 --- a/source/common/http/http_server_properties_cache_impl.cc +++ b/source/common/http/http_server_properties_cache_impl.cc @@ -296,6 +296,14 @@ HttpServerPropertiesCacheImpl::getOrCreateHttp3StatusTracker(const Origin& origi return *it->second.h3_status_tracker; } +void HttpServerPropertiesCacheImpl::resetBrokenness() { + for (auto& protocol : protocols_) { + if (protocol.second.h3_status_tracker && protocol.second.h3_status_tracker->isHttp3Broken()) { + protocol.second.h3_status_tracker->markHttp3FailedRecently(); + } + } +} + absl::string_view HttpServerPropertiesCacheImpl::getCanonicalSuffix(absl::string_view hostname) { for (const std::string& suffix : canonical_suffixes_) { if (absl::EndsWith(hostname, suffix)) { diff --git a/source/common/http/http_server_properties_cache_impl.h b/source/common/http/http_server_properties_cache_impl.h index 801fa958028e..d728f21b8267 100644 --- a/source/common/http/http_server_properties_cache_impl.h +++ b/source/common/http/http_server_properties_cache_impl.h @@ -91,6 +91,7 @@ class HttpServerPropertiesCacheImpl : public HttpServerPropertiesCache, size_t size() const override; HttpServerPropertiesCache::Http3StatusTracker& getOrCreateHttp3StatusTracker(const Origin& origin) override; + void resetBrokenness() override; private: // Time source used to check expiration of entries. diff --git a/source/common/http/http_server_properties_cache_manager_impl.cc b/source/common/http/http_server_properties_cache_manager_impl.cc index b9beaabcf024..13f717e64c22 100644 --- a/source/common/http/http_server_properties_cache_manager_impl.cc +++ b/source/common/http/http_server_properties_cache_manager_impl.cc @@ -73,5 +73,12 @@ HttpServerPropertiesCacheSharedPtr HttpServerPropertiesCacheManagerImpl::getCach return new_cache; } +void HttpServerPropertiesCacheManagerImpl::forEachThreadLocalCache(CacheFn cache_fn) { + for (auto& entry : (*slot_).caches_) { + HttpServerPropertiesCache& cache = *entry.second.cache_; + cache_fn(cache); + } +} + } // namespace Http } // namespace Envoy diff --git a/source/common/http/http_server_properties_cache_manager_impl.h b/source/common/http/http_server_properties_cache_manager_impl.h index 8ab68df28e3f..31ef6af80fa2 100644 --- a/source/common/http/http_server_properties_cache_manager_impl.h +++ b/source/common/http/http_server_properties_cache_manager_impl.h @@ -36,6 +36,8 @@ class HttpServerPropertiesCacheManagerImpl : public HttpServerPropertiesCacheMan getCache(const envoy::config::core::v3::AlternateProtocolsCacheOptions& options, Event::Dispatcher& dispatcher) override; + void forEachThreadLocalCache(CacheFn cache_fn) override; + private: // Contains a cache and the options associated with it. struct CacheWithOptions { diff --git a/source/common/http/null_route_impl.h b/source/common/http/null_route_impl.h index 6afaebf2e940..672dcc207d9a 100644 --- a/source/common/http/null_route_impl.h +++ b/source/common/http/null_route_impl.h @@ -103,6 +103,9 @@ struct RouteEntryImpl : public Router::RouteEntry { // Router::RouteEntry const std::string& clusterName() const override { return cluster_name_; } + const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const override { + return std::string(headers.getHostValue()); + } const Router::RouteStatsContextOptRef routeStatsContext() const override { return Router::RouteStatsContextOptRef(); } diff --git a/source/common/http/path_utility.cc b/source/common/http/path_utility.cc index ce5a88b1d037..c37b7473e25e 100644 --- a/source/common/http/path_utility.cc +++ b/source/common/http/path_utility.cc @@ -1,9 +1,9 @@ #include "source/common/http/path_utility.h" #include "source/common/common/logger.h" -#include "source/common/runtime/runtime_features.h" #include "absl/strings/str_join.h" +#include "absl/strings/str_replace.h" #include "absl/strings/str_split.h" #include "absl/types/optional.h" #include "url/url_canon.h" @@ -24,16 +24,6 @@ absl::optional canonicalizePath(absl::string_view original_path) { output.Complete(); return absl::make_optional(std::move(canonical_path)); } - -void unescapeInPath(std::string& path, absl::string_view escape_sequence, - absl::string_view substitution) { - std::vector split = absl::StrSplit(path, escape_sequence); - if (split.size() == 1) { - return; - } - path = absl::StrJoin(split, substitution); -} - } // namespace /* static */ @@ -92,13 +82,14 @@ PathUtil::UnescapeSlashesResult PathUtil::unescapeSlashes(RequestHeaderMap& head } const absl::string_view query = absl::ClippedSubstr(original_path, query_start); - // TODO(yanavlasov): optimize this by adding case insensitive matcher - std::string decoded_path{path}; - unescapeInPath(decoded_path, "%2F", "/"); - unescapeInPath(decoded_path, "%2f", "/"); - unescapeInPath(decoded_path, "%5C", "\\"); - unescapeInPath(decoded_path, "%5c", "\\"); - headers.setPath(absl::StrCat(decoded_path, query)); + static const std::vector> replacements{ + {"%2F", "/"}, + {"%2f", "/"}, + {"%5C", "\\"}, + {"%5c", "\\"}, + }; + headers.setPath(absl::StrCat(absl::StrReplaceAll(path, replacements), query)); + // Path length will not match if there were unescaped %2f or %5c return headers.getPathValue().length() != original_length ? UnescapeSlashesResult::FoundAndUnescaped diff --git a/source/common/http/status.cc b/source/common/http/status.cc index 967d8a6ae640..86117912c212 100644 --- a/source/common/http/status.cc +++ b/source/common/http/status.cc @@ -45,7 +45,7 @@ struct PrematureResponsePayload : public EnvoyStatusPayload { template void storePayload(absl::Status& status, const T& payload) { const T* allocated = new T(payload); const absl::string_view sv = - absl::string_view(reinterpret_cast(allocated), sizeof(allocated)); + absl::string_view(reinterpret_cast(allocated), sizeof(T)); absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); cord.Flatten(); // Flatten ahead of time for easier access later. status.SetPayload(EnvoyPayloadUrl, std::move(cord)); diff --git a/source/common/listener_manager/listener_manager_impl.cc b/source/common/listener_manager/listener_manager_impl.cc index f0841e119d3e..05ad90dcade9 100644 --- a/source/common/listener_manager/listener_manager_impl.cc +++ b/source/common/listener_manager/listener_manager_impl.cc @@ -474,7 +474,7 @@ ListenerManagerImpl::addOrUpdateListener(const envoy::config::listener::v3::List } if (!api_listener_ && !added_via_api) { auto listener_or_error = HttpApiListener::create(config, server_, config.name()); - RETURN_IF_STATUS_NOT_OK(listener_or_error); + RETURN_IF_NOT_OK_REF(listener_or_error.status()); api_listener_ = std::move(listener_or_error.value()); return true; } else { diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index c1d9131b260c..edfa56f6cc3d 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -231,16 +231,15 @@ Api::IoCallUint64Result IoSocketHandleImpl::sendmsg(const Buffer::RawSlice* slic Address::InstanceConstSharedPtr IoSocketHandleImpl::getOrCreateEnvoyAddressInstance(sockaddr_storage ss, socklen_t ss_len) { if (recent_received_addresses_ == nullptr) { - return Address::addressFromSockAddrOrDie(ss, ss_len, fd_, - socket_v6only_ || !udp_read_normalize_addresses_); + return Address::addressFromSockAddrOrDie(ss, ss_len, fd_, socket_v6only_); } quic::QuicSocketAddress quic_address(ss); auto it = recent_received_addresses_->Lookup(quic_address); if (it != recent_received_addresses_->end()) { return *it->second; } - Address::InstanceConstSharedPtr new_address = Address::addressFromSockAddrOrDie( - ss, ss_len, fd_, socket_v6only_ || !udp_read_normalize_addresses_); + Address::InstanceConstSharedPtr new_address = + Address::addressFromSockAddrOrDie(ss, ss_len, fd_, socket_v6only_); recent_received_addresses_->Insert( quic_address, std::make_unique(new_address)); return new_address; diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 3eb943a4157b..e919cc0c6bac 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -32,8 +32,6 @@ class IoSocketHandleImpl : public IoSocketHandleBaseImpl { absl::optional domain = absl::nullopt, size_t address_cache_max_capacity = 0) : IoSocketHandleBaseImpl(fd, socket_v6only, domain), - udp_read_normalize_addresses_( - Runtime::runtimeFeatureEnabled("envoy.restart_features.udp_read_normalize_addresses")), receive_ecn_(Runtime::runtimeFeatureEnabled("envoy.reloadable_features.quic_receive_ecn")) { if (address_cache_max_capacity > 0) { recent_received_addresses_ = @@ -108,8 +106,6 @@ class IoSocketHandleImpl : public IoSocketHandleBaseImpl { const size_t cmsg_space_{CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(uint16_t))}; - const bool udp_read_normalize_addresses_; - // Latches a copy of the runtime feature "envoy.reloadable_features.quic_receive_ecn". const bool receive_ecn_; diff --git a/source/common/network/resolver_impl.cc b/source/common/network/resolver_impl.cc index c336580b6697..7f7b5ece9686 100644 --- a/source/common/network/resolver_impl.cc +++ b/source/common/network/resolver_impl.cc @@ -87,7 +87,7 @@ resolveProtoSocketAddress(const envoy::config::core::v3::SocketAddress& socket_a return absl::InvalidArgumentError(fmt::format("Unknown address resolver: {}", resolver_name)); } auto instance_or_error = resolver->resolve(socket_address); - RETURN_IF_STATUS_NOT_OK(instance_or_error); + RETURN_IF_NOT_OK_REF(instance_or_error.status()); return std::move(instance_or_error.value()); } diff --git a/source/common/orca/BUILD b/source/common/orca/BUILD new file mode 100644 index 000000000000..fab411692e2b --- /dev/null +++ b/source/common/orca/BUILD @@ -0,0 +1,45 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "orca_parser", + srcs = ["orca_parser.cc"], + hdrs = ["orca_parser.h"], + external_deps = [ + "abseil_strings", + "abseil_statusor", + "fmtlib", + ], + deps = [ + "//envoy/http:header_map_interface", + "//source/common/common:base64_lib", + "@com_github_cncf_xds//xds/data/orca/v3:pkg_cc_proto", + ], +) + +envoy_cc_library( + name = "orca_load_metrics_lib", + srcs = ["orca_load_metrics.cc"], + hdrs = ["orca_load_metrics.h"], + external_deps = [ + "abseil_flat_hash_set", + "abseil_status", + "abseil_strings", + "abseil_statusor", + "fmtlib", + ], + deps = [ + ":orca_parser", + "//envoy/http:header_map_interface", + "//source/common/http:header_utility_lib", + "//source/common/protobuf:utility_lib_header", + "@com_github_cncf_xds//xds/data/orca/v3:pkg_cc_proto", + ], +) diff --git a/source/common/orca/orca_load_metrics.cc b/source/common/orca/orca_load_metrics.cc new file mode 100644 index 000000000000..9b931ff26380 --- /dev/null +++ b/source/common/orca/orca_load_metrics.cc @@ -0,0 +1,74 @@ +#include "source/common/orca/orca_load_metrics.h" + +#include + +#include "source/common/orca/orca_parser.h" + +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +namespace Envoy { +namespace Orca { +namespace { +// The following fields are the names of the metrics tracked in the ORCA load +// report proto. +static constexpr absl::string_view kApplicationUtilizationField = "application_utilization"; +static constexpr absl::string_view kCpuUtilizationField = "cpu_utilization"; +static constexpr absl::string_view kMemUtilizationField = "mem_utilization"; +static constexpr absl::string_view kEpsField = "eps"; +static constexpr absl::string_view kRpsFractionalField = "rps_fractional"; +static constexpr absl::string_view kNamedMetricsFieldPrefix = "named_metrics."; +static constexpr absl::string_view kRequestCostFieldPrefix = "request_cost."; +static constexpr absl::string_view kUtilizationFieldPrefix = "utilization."; +} // namespace + +void addOrcaNamedMetricToLoadMetricStats(const Protobuf::Map& metrics_map, + const absl::string_view metric_name, + const absl::string_view metric_name_prefix, + Upstream::LoadMetricStats& stats) { + absl::string_view metric_name_without_prefix = absl::StripPrefix(metric_name, metric_name_prefix); + // If the metric name is "*", add all metrics from the map. + if (metric_name_without_prefix == "*") { + for (const auto& [key, value] : metrics_map) { + stats.add(absl::StrCat(metric_name_prefix, key), value); + } + } else { + // Add the metric if it exists in the map. + const auto metric_it = metrics_map.find(metric_name_without_prefix); + if (metric_it != metrics_map.end()) { + stats.add(metric_name, metric_it->second); + } + } +} + +void addOrcaLoadReportToLoadMetricStats(const LrsReportMetricNames& metric_names, + const xds::data::orca::v3::OrcaLoadReport& report, + Upstream::LoadMetricStats& stats) { + // TODO(efimki): Use InlineMap to speed up this loop. + for (const std::string& metric_name : metric_names) { + if (metric_name == kCpuUtilizationField) { + stats.add(metric_name, report.cpu_utilization()); + } else if (metric_name == kMemUtilizationField) { + stats.add(metric_name, report.mem_utilization()); + } else if (metric_name == kApplicationUtilizationField) { + stats.add(metric_name, report.application_utilization()); + } else if (metric_name == kEpsField) { + stats.add(metric_name, report.eps()); + } else if (metric_name == kRpsFractionalField) { + stats.add(metric_name, report.rps_fractional()); + } else if (absl::StartsWith(metric_name, kNamedMetricsFieldPrefix)) { + addOrcaNamedMetricToLoadMetricStats(report.named_metrics(), metric_name, + kNamedMetricsFieldPrefix, stats); + } else if (absl::StartsWith(metric_name, kUtilizationFieldPrefix)) { + addOrcaNamedMetricToLoadMetricStats(report.utilization(), metric_name, + kUtilizationFieldPrefix, stats); + } else if (absl::StartsWith(metric_name, kRequestCostFieldPrefix)) { + addOrcaNamedMetricToLoadMetricStats(report.request_cost(), metric_name, + kRequestCostFieldPrefix, stats); + } + } +} + +} // namespace Orca +} // namespace Envoy diff --git a/source/common/orca/orca_load_metrics.h b/source/common/orca/orca_load_metrics.h new file mode 100644 index 000000000000..90c213ba1bf8 --- /dev/null +++ b/source/common/orca/orca_load_metrics.h @@ -0,0 +1,18 @@ +#pragma once + +#include "envoy/upstream/host_description.h" + +#include "xds/data/orca/v3/orca_load_report.pb.h" + +namespace Envoy { +namespace Orca { + +// List of metric names to report to the LRS. +typedef std::vector LrsReportMetricNames; + +void addOrcaLoadReportToLoadMetricStats(const LrsReportMetricNames& metric_names, + const xds::data::orca::v3::OrcaLoadReport& report, + Upstream::LoadMetricStats& stats); + +} // namespace Orca +} // namespace Envoy diff --git a/source/common/orca/orca_parser.cc b/source/common/orca/orca_parser.cc new file mode 100644 index 000000000000..73ba57da26d9 --- /dev/null +++ b/source/common/orca/orca_parser.cc @@ -0,0 +1,45 @@ +#include "source/common/orca/orca_parser.h" + +#include + +#include "envoy/http/header_map.h" + +#include "source/common/common/base64.h" +#include "source/common/common/fmt.h" + +#include "absl/strings/string_view.h" + +using ::Envoy::Http::HeaderMap; +using xds::data::orca::v3::OrcaLoadReport; + +namespace Envoy { +namespace Orca { + +namespace { + +const Http::LowerCaseString& endpointLoadMetricsHeaderBin() { + CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, kEndpointLoadMetricsHeaderBin); +} + +} // namespace + +absl::StatusOr parseOrcaLoadReportHeaders(const HeaderMap& headers) { + OrcaLoadReport load_report; + + // Binary protobuf format. + if (const auto header_bin = headers.get(endpointLoadMetricsHeaderBin()); !header_bin.empty()) { + const auto header_value = header_bin[0]->value().getStringView(); + const std::string decoded_value = Envoy::Base64::decode(header_value); + if (!load_report.ParseFromString(decoded_value)) { + return absl::InvalidArgumentError( + fmt::format("unable to parse binaryheader to OrcaLoadReport: {}", header_value)); + } + } else { + return absl::NotFoundError("no ORCA data sent from the backend"); + } + + return load_report; +} + +} // namespace Orca +} // namespace Envoy diff --git a/source/common/orca/orca_parser.h b/source/common/orca/orca_parser.h new file mode 100644 index 000000000000..86fd23944017 --- /dev/null +++ b/source/common/orca/orca_parser.h @@ -0,0 +1,19 @@ +#pragma once + +#include "envoy/http/header_map.h" + +#include "absl/status/statusor.h" +#include "xds/data/orca/v3/orca_load_report.pb.h" + +namespace Envoy { +namespace Orca { + +// Header used to send ORCA load metrics from the backend. +static constexpr absl::string_view kEndpointLoadMetricsHeaderBin = "endpoint-load-metrics-bin"; + +// Parses ORCA load metrics from a header map into an OrcaLoadReport proto. +// Supports serialized binary formats. +absl::StatusOr +parseOrcaLoadReportHeaders(const Envoy::Http::HeaderMap& headers); +} // namespace Orca +} // namespace Envoy diff --git a/source/common/protobuf/visitor.cc b/source/common/protobuf/visitor.cc index 6f16e6060d9b..f03a84e7f536 100644 --- a/source/common/protobuf/visitor.cc +++ b/source/common/protobuf/visitor.cc @@ -31,11 +31,11 @@ absl::Status traverseMessageWorker(ConstProtoVisitor& visitor, const Protobuf::M RETURN_IF_NOT_OK(MessageUtil::unpackTo(*any_message, *inner_message)); } else if (message.GetTypeName() == "xds.type.v3.TypedStruct") { auto output_or_error = Helper::convertTypedStruct(message); - RETURN_IF_STATUS_NOT_OK(output_or_error); + RETURN_IF_NOT_OK_REF(output_or_error.status()); std::tie(inner_message, target_type_url) = std::move(output_or_error.value()); } else if (message.GetTypeName() == "udpa.type.v1.TypedStruct") { auto output_or_error = Helper::convertTypedStruct(message); - RETURN_IF_STATUS_NOT_OK(output_or_error); + RETURN_IF_NOT_OK_REF(output_or_error.status()); std::tie(inner_message, target_type_url) = std::move(output_or_error.value()); } diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD index 8c4cded47bff..ecb713acc45d 100644 --- a/source/common/quic/BUILD +++ b/source/common/quic/BUILD @@ -258,6 +258,7 @@ envoy_cc_library( ":envoy_quic_simulated_watermark_buffer_lib", ":quic_network_connection_lib", ":quic_ssl_connection_info_lib", + ":quic_stat_names_lib", ":send_buffer_monitor_lib", "//envoy/event:dispatcher_interface", "//envoy/network:connection_interface", diff --git a/source/common/quic/active_quic_listener.cc b/source/common/quic/active_quic_listener.cc index 08aca091dd0c..735472bbddf6 100644 --- a/source/common/quic/active_quic_listener.cc +++ b/source/common/quic/active_quic_listener.cc @@ -78,9 +78,13 @@ ActiveQuicListener::ActiveQuicListener( socklen_t optlen = sizeof(optval); if (udp_listener_->localAddress()->ip()->ipv6() != nullptr) { listen_socket_.setSocketOption(IPPROTO_IPV6, IPV6_RECVTCLASS, &optval, optlen); +#ifndef __APPLE__ + // Linux dual-stack sockets require setting IP_RECVTOS separately. Apple + // sockets will return an error. if (!udp_listener_->localAddress()->ip()->ipv6()->v6only()) { listen_socket_.setSocketOption(IPPROTO_IP, IP_RECVTOS, &optval, optlen); } +#endif // __APPLE__ } else { listen_socket_.setSocketOption(IPPROTO_IP, IP_RECVTOS, &optval, optlen); } diff --git a/source/common/quic/envoy_quic_client_session.cc b/source/common/quic/envoy_quic_client_session.cc index b6ac762f7b43..aed2ac6115d8 100644 --- a/source/common/quic/envoy_quic_client_session.cc +++ b/source/common/quic/envoy_quic_client_session.cc @@ -85,12 +85,12 @@ EnvoyQuicClientSession::EnvoyQuicClientSession( std::make_unique( dispatcher.timeSource(), connection->connectionSocket()->connectionInfoProviderSharedPtr(), - StreamInfo::FilterState::LifeSpan::Connection)), + StreamInfo::FilterState::LifeSpan::Connection), + quic_stat_names, scope), quic::QuicSpdyClientSession(config, supported_versions, connection.release(), server_id, crypto_config.get()), crypto_config_(crypto_config), crypto_stream_factory_(crypto_stream_factory), - quic_stat_names_(quic_stat_names), rtt_cache_(rtt_cache), scope_(scope), - transport_socket_options_(transport_socket_options), + rtt_cache_(rtt_cache), transport_socket_options_(transport_socket_options), transport_socket_factory_(makeOptRefFromPtr( dynamic_cast(transport_socket_factory.ptr()))) { streamInfo().setUpstreamInfo(std::make_shared()); @@ -137,7 +137,8 @@ void EnvoyQuicClientSession::OnConnectionClosed(const quic::QuicConnectionCloseF } } quic::QuicSpdyClientSession::OnConnectionClosed(frame, source); - quic_stat_names_.chargeQuicConnectionCloseStats(scope_, frame.quic_error_code, source, true); + quic_stat_names_.chargeQuicConnectionCloseStats(stats_scope_, frame.quic_error_code, source, + true); onConnectionCloseEvent(frame, source, version()); } @@ -163,18 +164,10 @@ void EnvoyQuicClientSession::OnHttp3GoAway(uint64_t stream_id) { } } -void EnvoyQuicClientSession::MaybeSendRstStreamFrame(quic::QuicStreamId id, - quic::QuicResetStreamError error, - quic::QuicStreamOffset bytes_written) { - QuicSpdyClientSession::MaybeSendRstStreamFrame(id, error, bytes_written); - quic_stat_names_.chargeQuicResetStreamErrorStats(scope_, error, /*from_self*/ true, - /*is_upstream*/ true); -} - void EnvoyQuicClientSession::OnRstStream(const quic::QuicRstStreamFrame& frame) { QuicSpdyClientSession::OnRstStream(frame); - quic_stat_names_.chargeQuicResetStreamErrorStats(scope_, frame.error(), - /*from_self*/ false, /*is_upstream*/ true); + incrementSentQuicResetStreamErrorStats(frame.error(), + /*from_self*/ false, /*is_upstream*/ true); } void EnvoyQuicClientSession::OnCanCreateNewOutgoingStream(bool unidirectional) { diff --git a/source/common/quic/envoy_quic_client_session.h b/source/common/quic/envoy_quic_client_session.h index 5e88f53e60d8..5ef804e3e8ea 100644 --- a/source/common/quic/envoy_quic_client_session.h +++ b/source/common/quic/envoy_quic_client_session.h @@ -59,8 +59,6 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, void OnCanWrite() override; void OnHttp3GoAway(uint64_t stream_id) override; void OnTlsHandshakeComplete() override; - void MaybeSendRstStreamFrame(quic::QuicStreamId id, quic::QuicResetStreamError error, - quic::QuicStreamOffset bytes_written) override; void OnRstStream(const quic::QuicRstStreamFrame& frame) override; void OnNewEncryptionKeyAvailable(quic::EncryptionLevel level, std::unique_ptr encrypter) override; @@ -118,9 +116,7 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, Http::ConnectionCallbacks* http_connection_callbacks_{nullptr}; std::shared_ptr crypto_config_; EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory_; - QuicStatNames& quic_stat_names_; OptRef rtt_cache_; - Stats::Scope& scope_; bool disable_keepalive_{false}; Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; OptRef transport_socket_factory_; diff --git a/source/common/quic/envoy_quic_client_stream.cc b/source/common/quic/envoy_quic_client_stream.cc index 3e329da66541..848817777945 100644 --- a/source/common/quic/envoy_quic_client_stream.cc +++ b/source/common/quic/envoy_quic_client_stream.cc @@ -369,6 +369,8 @@ void EnvoyQuicClientStream::OnStreamReset(const quic::QuicRstStreamFrame& frame) void EnvoyQuicClientStream::ResetWithError(quic::QuicResetStreamError error) { ENVOY_STREAM_LOG(debug, "sending reset code={}", *this, error.internal_code()); stats_.tx_reset_.inc(); + filterManagerConnection()->incrementSentQuicResetStreamErrorStats(error, /*from_self*/ true, + /*is_upstream*/ true); // Upper layers expect calling resetStream() to immediately raise reset callbacks. runResetCallbacks( quicRstErrorToEnvoyLocalResetReason(error.internal_code()), diff --git a/source/common/quic/envoy_quic_dispatcher.cc b/source/common/quic/envoy_quic_dispatcher.cc index eb295704956d..b7b5ac42ebde 100644 --- a/source/common/quic/envoy_quic_dispatcher.cc +++ b/source/common/quic/envoy_quic_dispatcher.cc @@ -181,24 +181,17 @@ void EnvoyQuicDispatcher::closeConnectionsWithFilterChain( // Retain the number of connections in the list early because closing the connection will change // the size. const size_t num_connections = connections.size(); - bool delete_sessions_immediately = false; for (size_t i = 0; i < num_connections; ++i) { Network::Connection& connection = connections.front().get(); // This will remove the connection from the list. And the last removal will remove connections // from the map as well. connection.close(Network::ConnectionCloseType::NoFlush); - if (!delete_sessions_immediately && - dynamic_cast(connection).fixQuicLifetimeIssues()) { - // If `envoy.reloadable_features.quic_fix_filter_manager_uaf` is true, the closed sessions - // need to be deleted right away to consistently handle quic lifetimes. Because upon - // returning the filter chain configs will be destroyed, and no longer safe to be accessed. - // If any filters access those configs during destruction, it'll be use-after-free - delete_sessions_immediately = true; - } } ASSERT(connections_by_filter_chain_.find(filter_chain) == connections_by_filter_chain_.end()); - if (delete_sessions_immediately) { - // Explicitly destroy closed sessions in the current call stack. + if (num_connections > 0) { + // Explicitly destroy closed sessions in the current call stack. Because upon + // returning the filter chain configs will be destroyed, and no longer safe to be accessed. + // If any filters access those configs during destruction, it'll be use-after-free DeleteSessions(); } } diff --git a/source/common/quic/envoy_quic_proof_verifier.cc b/source/common/quic/envoy_quic_proof_verifier.cc index 0ae8f324eb8b..330da858d75a 100644 --- a/source/common/quic/envoy_quic_proof_verifier.cc +++ b/source/common/quic/envoy_quic_proof_verifier.cc @@ -36,9 +36,10 @@ class QuicValidateResultCallback : public Ssl::ValidateResultCallback { public: QuicValidateResultCallback(Event::Dispatcher& dispatcher, std::unique_ptr&& quic_callback, - const std::string& hostname, const std::string& leaf_cert) + const std::string& hostname, const std::string& leaf_cert, + bool accept_untrusted) : dispatcher_(dispatcher), quic_callback_(std::move(quic_callback)), hostname_(hostname), - leaf_cert_(leaf_cert) {} + leaf_cert_(leaf_cert), accept_untrusted_(accept_untrusted) {} Event::Dispatcher& dispatcher() override { return dispatcher_; } @@ -47,7 +48,8 @@ class QuicValidateResultCallback : public Ssl::ValidateResultCallback { std::string error; if (!succeeded) { error = error_details; - } else { + } else if (!accept_untrusted_ || !Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.extend_h3_accept_untrusted")) { std::unique_ptr cert_view = quic::CertificateView::ParseSingleCertificate(leaf_cert_); succeeded = verifyLeafCertMatchesHostname(*cert_view, hostname_, &error); @@ -63,6 +65,7 @@ class QuicValidateResultCallback : public Ssl::ValidateResultCallback { const std::string hostname_; // Leaf cert needs to be retained in case of asynchronous validation. std::string leaf_cert_; + const bool accept_untrusted_; }; } // namespace @@ -101,7 +104,7 @@ quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain( } auto envoy_callback = std::make_unique( - verify_context->dispatcher(), std::move(callback), hostname, certs[0]); + verify_context->dispatcher(), std::move(callback), hostname, certs[0], accept_untrusted_); ASSERT(dynamic_cast(context_.get()) != nullptr); // We down cast rather than add customVerifyCertChainForQuic to Envoy::Ssl::Context because diff --git a/source/common/quic/envoy_quic_proof_verifier.h b/source/common/quic/envoy_quic_proof_verifier.h index b42e9841a709..b5af84ae3c4f 100644 --- a/source/common/quic/envoy_quic_proof_verifier.h +++ b/source/common/quic/envoy_quic_proof_verifier.h @@ -39,8 +39,9 @@ using EnvoyQuicProofVerifyContextPtr = std::unique_ptrconnection_id(), dispatcher, send_buffer_limit, - std::make_shared(*this), std::move(stream_info)), - quic_connection_(std::move(connection)), quic_stat_names_(quic_stat_names), - listener_scope_(listener_scope), crypto_server_stream_factory_(crypto_server_stream_factory), + QuicFilterManagerConnectionImpl(*connection, connection->connection_id(), dispatcher, + send_buffer_limit, + std::make_shared(*this), + std::move(stream_info), quic_stat_names, listener_scope), + quic_connection_(std::move(connection)), + crypto_server_stream_factory_(crypto_server_stream_factory), connection_stats_(connection_stats) { #ifdef ENVOY_ENABLE_HTTP_DATAGRAMS http_datagram_support_ = quic::HttpDatagramSupport::kRfc; @@ -175,18 +176,10 @@ void EnvoyQuicServerSession::OnTlsHandshakeComplete() { raiseConnectionEvent(Network::ConnectionEvent::Connected); } -void EnvoyQuicServerSession::MaybeSendRstStreamFrame(quic::QuicStreamId id, - quic::QuicResetStreamError error, - quic::QuicStreamOffset bytes_written) { - QuicServerSessionBase::MaybeSendRstStreamFrame(id, error, bytes_written); - quic_stat_names_.chargeQuicResetStreamErrorStats(listener_scope_, error, /*from_self*/ true, - /*is_upstream*/ false); -} - void EnvoyQuicServerSession::OnRstStream(const quic::QuicRstStreamFrame& frame) { QuicServerSessionBase::OnRstStream(frame); - quic_stat_names_.chargeQuicResetStreamErrorStats(listener_scope_, frame.error(), - /*from_self*/ false, /*is_upstream*/ false); + incrementSentQuicResetStreamErrorStats(frame.error(), + /*from_self*/ false, /*is_upstream*/ false); } void EnvoyQuicServerSession::setHttp3Options( diff --git a/source/common/quic/envoy_quic_server_session.h b/source/common/quic/envoy_quic_server_session.h index 05ee14081129..62014e9d8854 100644 --- a/source/common/quic/envoy_quic_server_session.h +++ b/source/common/quic/envoy_quic_server_session.h @@ -82,8 +82,6 @@ class EnvoyQuicServerSession : public quic::QuicServerSessionBase, void Initialize() override; void OnCanWrite() override; void OnTlsHandshakeComplete() override; - void MaybeSendRstStreamFrame(quic::QuicStreamId id, quic::QuicResetStreamError error, - quic::QuicStreamOffset bytes_written) override; void OnRstStream(const quic::QuicRstStreamFrame& frame) override; void ProcessUdpPacket(const quic::QuicSocketAddress& self_address, const quic::QuicSocketAddress& peer_address, @@ -137,9 +135,6 @@ class EnvoyQuicServerSession : public quic::QuicServerSessionBase, envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction headers_with_underscores_action_; - QuicStatNames& quic_stat_names_; - Stats::Scope& listener_scope_; - EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory_; absl::optional position_; QuicConnectionStats& connection_stats_; diff --git a/source/common/quic/envoy_quic_server_stream.cc b/source/common/quic/envoy_quic_server_stream.cc index 812025913c59..f3ca7a38a3e3 100644 --- a/source/common/quic/envoy_quic_server_stream.cc +++ b/source/common/quic/envoy_quic_server_stream.cc @@ -359,6 +359,8 @@ void EnvoyQuicServerStream::OnStreamReset(const quic::QuicRstStreamFrame& frame) void EnvoyQuicServerStream::ResetWithError(quic::QuicResetStreamError error) { ENVOY_STREAM_LOG(debug, "sending reset code={}", *this, error.internal_code()); stats_.tx_reset_.inc(); + filterManagerConnection()->incrementSentQuicResetStreamErrorStats(error, /*from_self*/ true, + /*is_upstream*/ false); if (!local_end_stream_) { // Upper layers expect calling resetStream() to immediately raise reset callbacks. runResetCallbacks( diff --git a/source/common/quic/envoy_quic_stream.cc b/source/common/quic/envoy_quic_stream.cc index 280c7ab91513..12d7a1b20f5b 100644 --- a/source/common/quic/envoy_quic_stream.cc +++ b/source/common/quic/envoy_quic_stream.cc @@ -123,8 +123,8 @@ std::unique_ptr dataFromString(const std::string& str) { void serializeMetadata(const Http::MetadataMapPtr& metadata, quic::QuicStreamId id, absl::InlinedVector& slices) { quic::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; - quic::QpackEncoder qpack_encoder(&decoder_stream_error_delegate, - quic::HuffmanEncoding::kDisabled); + quic::QpackEncoder qpack_encoder(&decoder_stream_error_delegate, quic::HuffmanEncoding::kDisabled, + quic::CookieCrumbling::kDisabled); spdy::Http2HeaderBlock header_block; for (const auto& [key, value] : *metadata) { diff --git a/source/common/quic/platform/quiche_export_impl.h b/source/common/quic/platform/quiche_export_impl.h index 9cb2788428fe..ae460cf0b700 100644 --- a/source/common/quic/platform/quiche_export_impl.h +++ b/source/common/quic/platform/quiche_export_impl.h @@ -18,5 +18,4 @@ #define QUICHE_EXPORT_IMPL #endif -#define QUICHE_EXPORT_PRIVATE_IMPL QUICHE_EXPORT_IMPL #define QUICHE_NO_EXPORT_IMPL QUICHE_EXPORT_IMPL diff --git a/source/common/quic/quic_client_transport_socket_factory.cc b/source/common/quic/quic_client_transport_socket_factory.cc index 091c85a170c1..e7b2febc8f75 100644 --- a/source/common/quic/quic_client_transport_socket_factory.cc +++ b/source/common/quic/quic_client_transport_socket_factory.cc @@ -76,10 +76,15 @@ std::shared_ptr QuicClientTransportSocketFactory:: ThreadLocalQuicConfig& tls_config = *tls_slot_; if (tls_config.client_context_ != context) { + bool accept_untrusted = + clientContextConfig() && clientContextConfig()->certificateValidationContext() && + clientContextConfig()->certificateValidationContext()->trustChainVerification() == + envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext:: + ACCEPT_UNTRUSTED; // If the context has been updated, update the crypto config. tls_config.client_context_ = context; tls_config.crypto_config_ = std::make_shared( - std::make_unique(std::move(context)), + std::make_unique(std::move(context), accept_untrusted), std::make_unique()); } // Return the latest crypto config. diff --git a/source/common/quic/quic_filter_manager_connection_impl.cc b/source/common/quic/quic_filter_manager_connection_impl.cc index c616affb15b2..520cb822a51a 100644 --- a/source/common/quic/quic_filter_manager_connection_impl.cc +++ b/source/common/quic/quic_filter_manager_connection_impl.cc @@ -13,11 +13,13 @@ QuicFilterManagerConnectionImpl::QuicFilterManagerConnectionImpl( QuicNetworkConnection& connection, const quic::QuicConnectionId& connection_id, Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, std::shared_ptr&& info, - std::unique_ptr&& stream_info) + std::unique_ptr&& stream_info, QuicStatNames& quic_stat_names, + Stats::Scope& stats_scope) // Using this for purpose other than logging is not safe. Because QUIC connection id can be // 18 bytes, so there might be collision when it's hashed to 8 bytes. : Network::ConnectionImplBase(dispatcher, /*id=*/connection_id.Hash()), network_connection_(&connection), quic_ssl_info_(std::move(info)), + quic_stat_names_(quic_stat_names), stats_scope_(stats_scope), filter_manager_( std::make_unique(*this, *connection.connectionSocket())), stream_info_(std::move(stream_info)), @@ -28,8 +30,6 @@ QuicFilterManagerConnectionImpl::QuicFilterManagerConnectionImpl( network_connection_->connectionSocket()->connectionInfoProvider().setConnectionID(id()); network_connection_->connectionSocket()->connectionInfoProvider().setSslConnection( Ssl::ConnectionInfoConstSharedPtr(quic_ssl_info_)); - fix_quic_lifetime_issues_ = - Runtime::runtimeFeatureEnabled("envoy.reloadable_features.quic_fix_filter_manager_uaf"); } void QuicFilterManagerConnectionImpl::addWriteFilter(Network::WriteFilterSharedPtr filter) { @@ -182,9 +182,6 @@ void QuicFilterManagerConnectionImpl::onConnectionCloseEvent( network_connection_ = nullptr; } - if (!fix_quic_lifetime_issues_) { - filter_manager_ = nullptr; - } if (!codec_stats_.has_value()) { // The connection was closed before it could be used. Stats are not recorded. return; @@ -276,5 +273,10 @@ void QuicFilterManagerConnectionImpl::maybeHandleCloseDuringInitialize() { } } +void QuicFilterManagerConnectionImpl::incrementSentQuicResetStreamErrorStats( + quic::QuicResetStreamError error, bool from_self, bool is_upstream) { + quic_stat_names_.chargeQuicResetStreamErrorStats(stats_scope_, error, from_self, is_upstream); +} + } // namespace Quic } // namespace Envoy diff --git a/source/common/quic/quic_filter_manager_connection_impl.h b/source/common/quic/quic_filter_manager_connection_impl.h index 432f2779673b..da591a31b86b 100644 --- a/source/common/quic/quic_filter_manager_connection_impl.h +++ b/source/common/quic/quic_filter_manager_connection_impl.h @@ -13,6 +13,7 @@ #include "source/common/quic/envoy_quic_simulated_watermark_buffer.h" #include "source/common/quic/quic_network_connection.h" #include "source/common/quic/quic_ssl_connection_info.h" +#include "source/common/quic/quic_stat_names.h" #include "source/common/quic/send_buffer_monitor.h" #include "source/common/stream_info/stream_info_impl.h" @@ -35,7 +36,8 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase, const quic::QuicConnectionId& connection_id, Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, std::shared_ptr&& info, - std::unique_ptr&& stream_info); + std::unique_ptr&& stream_info, + QuicStatNames& quic_stat_names, Stats::Scope& stats_scope); // Network::FilterManager // Overridden to delegate calls to filter_manager_. void addWriteFilter(Network::WriteFilterSharedPtr filter) override; @@ -171,7 +173,8 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase, max_headers_count_ = max_headers_count; } - bool fixQuicLifetimeIssues() const { return fix_quic_lifetime_issues_; } + void incrementSentQuicResetStreamErrorStats(quic::QuicResetStreamError error, bool from_self, + bool is_upstream); protected: // Propagate connection close to network_connection_callbacks_. @@ -199,6 +202,8 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase, OptRef http3_options_; bool initialized_{false}; std::shared_ptr quic_ssl_info_; + QuicStatNames& quic_stat_names_; + Stats::Scope& stats_scope_; private: friend class Envoy::TestPauseFilterForQuic; @@ -226,7 +231,6 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase, EnvoyQuicSimulatedWatermarkBuffer write_buffer_watermark_simulation_; Buffer::OwnedImpl empty_buffer_; absl::optional close_type_during_initialize_; - bool fix_quic_lifetime_issues_{false}; }; } // namespace Quic diff --git a/source/common/router/BUILD b/source/common/router/BUILD index 65458851c98a..70200e05eaff 100644 --- a/source/common/router/BUILD +++ b/source/common/router/BUILD @@ -366,6 +366,8 @@ envoy_cc_library( "//source/common/network:socket_option_factory_lib", "//source/common/network:transport_socket_options_lib", "//source/common/network:upstream_socket_options_filter_state_lib", + "//source/common/orca:orca_load_metrics_lib", + "//source/common/orca:orca_parser", "//source/common/stream_info:stream_info_lib", "//source/common/stream_info:uint32_accessor_lib", "//source/common/tracing:http_tracer_lib", diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 51bb67a87147..0d4b12862985 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -53,6 +53,7 @@ #include "source/extensions/path/match/uri_template/uri_template_match.h" #include "source/extensions/path/rewrite/uri_template/uri_template_rewrite.h" +#include "absl/container/inlined_vector.h" #include "absl/strings/match.h" namespace Envoy { @@ -671,9 +672,9 @@ RouteEntryImplBase::RouteEntryImplBase(const CommonVirtualHostSharedPtr& vhost, return; } - weighted_clusters_config_ = - std::make_unique(std::move(weighted_clusters), total_weight, - route.route().weighted_clusters().header_name()); + weighted_clusters_config_ = std::make_unique( + std::move(weighted_clusters), total_weight, route.route().weighted_clusters().header_name(), + route.route().weighted_clusters().runtime_key_prefix()); } else if (route.route().cluster_specifier_case() == envoy::config::route::v3::RouteAction::ClusterSpecifierCase:: @@ -905,6 +906,32 @@ bool RouteEntryImplBase::matchRoute(const Http::RequestHeaderMap& headers, const std::string& RouteEntryImplBase::clusterName() const { return cluster_name_; } +const std::string +RouteEntryImplBase::getRequestHostValue(const Http::RequestHeaderMap& headers) const { + if (!host_rewrite_.empty()) { + return host_rewrite_; + } + + if (auto_host_rewrite_header_) { + const auto& header = headers.get(*auto_host_rewrite_header_); + if (!header.empty()) { + const absl::string_view header_value = header[0]->value().getStringView(); + if (!header_value.empty()) { + return std::string(header_value); + } + } + } + + if (host_rewrite_path_regex_) { + absl::string_view path = headers.getPathValue(); + return host_rewrite_path_regex_->replaceAll(Http::PathUtil::removeQueryAndFragment(path), + host_rewrite_path_regex_substitution_); + } + + // Fallback to original host value + return std::string(headers.getHostValue()); +} + void RouteEntryImplBase::finalizeRequestHeaders(Http::RequestHeaderMap& headers, const StreamInfo::StreamInfo& stream_info, bool insert_envoy_original_path) const { @@ -925,25 +952,9 @@ void RouteEntryImplBase::finalizeRequestHeaders(Http::RequestHeaderMap& headers, } } - if (!host_rewrite_.empty()) { - Http::Utility::updateAuthority(headers, host_rewrite_, append_xfh_); - } else if (auto_host_rewrite_header_) { - const auto header = headers.get(*auto_host_rewrite_header_); - if (!header.empty()) { - // This is an implicitly untrusted header, so per the API documentation only the first - // value is used. - const absl::string_view header_value = header[0]->value().getStringView(); - if (!header_value.empty()) { - Http::Utility::updateAuthority(headers, header_value, append_xfh_); - } - } - } else if (host_rewrite_path_regex_ != nullptr) { - const std::string path(headers.getPathValue()); - absl::string_view just_path(Http::PathUtil::removeQueryAndFragment(path)); - Http::Utility::updateAuthority( - headers, - host_rewrite_path_regex_->replaceAll(just_path, host_rewrite_path_regex_substitution_), - append_xfh_); + auto final_host_value = getRequestHostValue(headers); + if (final_host_value != headers.getHostValue()) { + Http::Utility::updateAuthority(headers, final_host_value, append_xfh_); } // Handle path rewrite @@ -1253,7 +1264,7 @@ RouteEntryImplBase::buildPathRewriter(envoy::config::route::v3::Route route, route.route().path_rewrite_policy().typed_config(), validator, factory); absl::StatusOr rewriter = factory.createPathRewriter(*config); - RETURN_IF_STATUS_NOT_OK(rewriter); + RETURN_IF_NOT_OK_REF(rewriter.status()); return rewriter.value(); } @@ -1271,7 +1282,7 @@ RouteEntryImplBase::buildPathMatcher(envoy::config::route::v3::Route route, route.match().path_match_policy().typed_config(), validator, factory); absl::StatusOr matcher = factory.createPathMatcher(*config); - RETURN_IF_STATUS_NOT_OK(matcher); + RETURN_IF_NOT_OK_REF(matcher.status()); return matcher.value(); } @@ -1347,12 +1358,15 @@ RouteConstSharedPtr RouteEntryImplBase::clusterEntry(const Http::RequestHeaderMa return cluster_specifier_plugin_->route(shared_from_this(), headers); } } - return pickWeightedCluster(headers, random_value, true); + return pickWeightedCluster(headers, random_value); } +// Selects a cluster depending on weight parameters from configuration or from headers. +// This function takes into account the weights set through configuration or through +// runtime parameters. +// Returns selected cluster, or nullptr if weighted configuration is invalid. RouteConstSharedPtr RouteEntryImplBase::pickWeightedCluster(const Http::HeaderMap& headers, - const uint64_t random_value, - const bool ignore_overflow) const { + const uint64_t random_value) const { absl::optional random_value_from_header; // Retrieve the random value from the header if corresponding header name is specified. // weighted_clusters_config_ is known not to be nullptr here. If it were, pickWeightedCluster @@ -1380,23 +1394,55 @@ RouteConstSharedPtr RouteEntryImplBase::pickWeightedCluster(const Http::HeaderMa } } + auto runtime_key_prefix_configured = + (weighted_clusters_config_->runtime_key_prefix_.length() ? true : false); + uint32_t total_cluster_weight = weighted_clusters_config_->total_cluster_weight_; + absl::InlinedVector cluster_weights; + + // if runtime config is used, we need to recompute total_weight + if (runtime_key_prefix_configured) { + // Temporary storage to hold consistent cluster weights. Since cluster weight + // can be changed with runtime keys, we need a way to gather all the weight + // and aggregate the total without a change in between. + // The InlinedVector will be able to handle at least 4 cluster weights + // without allocation. For cases when more clusters are needed, it is + // reserved to ensure at most a single allocation. + cluster_weights.reserve(weighted_clusters_config_->weighted_clusters_.size()); + + total_cluster_weight = 0; + for (const WeightedClusterEntrySharedPtr& cluster : + weighted_clusters_config_->weighted_clusters_) { + auto cluster_weight = cluster->clusterWeight(); + cluster_weights.push_back(cluster_weight); + if (cluster_weight > std::numeric_limits::max() - total_cluster_weight) { + IS_ENVOY_BUG("Sum of weight cannot overflow 2^32"); + return nullptr; + } + total_cluster_weight += cluster_weight; + } + } + + if (total_cluster_weight == 0) { + IS_ENVOY_BUG("Sum of weight cannot be zero"); + return nullptr; + } const uint64_t selected_value = (random_value_from_header.has_value() ? random_value_from_header.value() : random_value) % - weighted_clusters_config_->total_cluster_weight_; + total_cluster_weight; uint64_t begin = 0; uint64_t end = 0; + auto cluster_weight = cluster_weights.begin(); // Find the right cluster to route to based on the interval in which // the selected value falls. The intervals are determined as // [0, cluster1_weight), [cluster1_weight, cluster1_weight+cluster2_weight),.. for (const WeightedClusterEntrySharedPtr& cluster : weighted_clusters_config_->weighted_clusters_) { - end = begin + cluster->clusterWeight(); - if (!ignore_overflow) { - // end > total_cluster_weight: This case can only occur with Runtimes, - // when the user specifies invalid weights such that - // sum(weights) > total_cluster_weight. - ASSERT(end <= weighted_clusters_config_->total_cluster_weight_); + + if (runtime_key_prefix_configured) { + end = begin + *cluster_weight++; + } else { + end = begin + cluster->clusterWeight(); } if (selected_value >= begin && selected_value < end) { @@ -1415,7 +1461,8 @@ RouteConstSharedPtr RouteEntryImplBase::pickWeightedCluster(const Http::HeaderMa begin = end; } - PANIC("unexpected"); + IS_ENVOY_BUG("unexpected"); + return nullptr; } absl::Status RouteEntryImplBase::validateClusters( diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index 2a6bfc723532..36b0e26dc6f4 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -682,6 +682,7 @@ class RouteEntryImplBase : public RouteEntryAndRoute, // Router::RouteEntry const std::string& clusterName() const override; + const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const override; const RouteStatsContextOptRef routeStatsContext() const override { if (route_stats_context_ != nullptr) { return *route_stats_context_; @@ -851,6 +852,9 @@ class RouteEntryImplBase : public RouteEntryAndRoute, // Router::RouteEntry const std::string& clusterName() const override { return cluster_name_; } + const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const override { + return parent_->getRequestHostValue(headers); + } Http::Code clusterNotFoundResponseCode() const override { return parent_->clusterNotFoundResponseCode(); } @@ -1089,13 +1093,16 @@ class RouteEntryImplBase : public RouteEntryAndRoute, struct WeightedClustersConfig { WeightedClustersConfig(const std::vector&& weighted_clusters, uint64_t total_cluster_weight, - const std::string& random_value_header_name) + const std::string& random_value_header_name, + const std::string& runtime_key_prefix) : weighted_clusters_(std::move(weighted_clusters)), total_cluster_weight_(total_cluster_weight), - random_value_header_name_(random_value_header_name) {} + random_value_header_name_(random_value_header_name), + runtime_key_prefix_(runtime_key_prefix) {} const std::vector weighted_clusters_; const uint64_t total_cluster_weight_; const std::string random_value_header_name_; + const std::string runtime_key_prefix_; }; protected: @@ -1207,8 +1214,8 @@ class RouteEntryImplBase : public RouteEntryAndRoute, const Http::HeaderMap& headers, const RouteEntryAndRoute* route_selector_override) const; - RouteConstSharedPtr pickWeightedCluster(const Http::HeaderMap& headers, uint64_t random_value, - bool ignore_overflow) const; + RouteConstSharedPtr pickWeightedCluster(const Http::HeaderMap& headers, + uint64_t random_value) const; // Default timeout is 15s if nothing is specified in the route config. static const uint64_t DEFAULT_ROUTE_TIMEOUT_MS = 15000; diff --git a/source/common/router/delegating_route_impl.cc b/source/common/router/delegating_route_impl.cc index 4b7afc9fee77..b8d5d903dc6a 100644 --- a/source/common/router/delegating_route_impl.cc +++ b/source/common/router/delegating_route_impl.cc @@ -32,6 +32,11 @@ const std::string& DelegatingRouteEntry::clusterName() const { return base_route_->routeEntry()->clusterName(); } +const std::string +DelegatingRouteEntry::getRequestHostValue(const Http::RequestHeaderMap& headers) const { + return base_route_->routeEntry()->getRequestHostValue(headers); +} + Http::Code DelegatingRouteEntry::clusterNotFoundResponseCode() const { return base_route_->routeEntry()->clusterNotFoundResponseCode(); } diff --git a/source/common/router/delegating_route_impl.h b/source/common/router/delegating_route_impl.h index 91d0b99f86c1..36deb173c7f9 100644 --- a/source/common/router/delegating_route_impl.h +++ b/source/common/router/delegating_route_impl.h @@ -74,6 +74,7 @@ class DelegatingRouteEntry : public Router::RouteEntry { // Router::RouteEntry const std::string& clusterName() const override; + const std::string getRequestHostValue(const Http::RequestHeaderMap& headers) const override; Http::Code clusterNotFoundResponseCode() const override; const CorsPolicy* corsPolicy() const override; absl::optional diff --git a/source/common/router/header_parser.cc b/source/common/router/header_parser.cc index cd8e9b5ee893..4d33c0ce4580 100644 --- a/source/common/router/header_parser.cc +++ b/source/common/router/header_parser.cc @@ -89,7 +89,7 @@ HeaderParser::configure(const Protobuf::RepeatedPtrField& hea HeaderParserPtr header_parser(new HeaderParser()); for (const auto& header_value_option : headers_to_add) { auto entry_or_error = HeadersToAddEntry::create(header_value_option); - RETURN_IF_STATUS_NOT_OK(entry_or_error); + RETURN_IF_NOT_OK_REF(entry_or_error.status()); header_parser->headers_to_add_.emplace_back( Http::LowerCaseString(header_value_option.header().key()), std::move(entry_or_error.value())); @@ -105,7 +105,7 @@ absl::StatusOr HeaderParser::configure( for (const auto& header_value : headers_to_add) { auto entry_or_error = HeadersToAddEntry::create(header_value, append_action); - RETURN_IF_STATUS_NOT_OK(entry_or_error); + RETURN_IF_NOT_OK_REF(entry_or_error.status()); header_parser->headers_to_add_.emplace_back(Http::LowerCaseString(header_value.key()), std::move(entry_or_error.value())); } @@ -117,7 +117,7 @@ absl::StatusOr HeaderParser::configure(const Protobuf::RepeatedPtrField& headers_to_add, const Protobuf::RepeatedPtrField& headers_to_remove) { auto parser_or_error = configure(headers_to_add); - RETURN_IF_STATUS_NOT_OK(parser_or_error); + RETURN_IF_NOT_OK_REF(parser_or_error.status()); HeaderParserPtr header_parser = std::move(parser_or_error.value()); for (const auto& header : headers_to_remove) { diff --git a/source/common/router/rds_impl.cc b/source/common/router/rds_impl.cc index 78409903f215..43cb301978ea 100644 --- a/source/common/router/rds_impl.cc +++ b/source/common/router/rds_impl.cc @@ -50,7 +50,7 @@ absl::Status RdsRouteConfigSubscription::beforeProviderUpdate( resume_rds); auto subscription_or_error = VhdsSubscription::createVhdsSubscription( config_update_info_, factory_context_, stat_prefix_, route_config_provider_); - RETURN_IF_STATUS_NOT_OK(subscription_or_error); + RETURN_IF_NOT_OK_REF(subscription_or_error.status()); vhds_subscription_ = std::move(subscription_or_error.value()); vhds_subscription_->registerInitTargetWithInitManager( noop_init_manager == nullptr ? local_init_manager_ : *noop_init_manager); diff --git a/source/common/router/router.cc b/source/common/router/router.cc index 1a940b5db2a8..05ad0e6430c4 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -35,6 +35,8 @@ #include "source/common/network/upstream_server_name.h" #include "source/common/network/upstream_socket_options_filter_state.h" #include "source/common/network/upstream_subject_alt_names.h" +#include "source/common/orca/orca_load_metrics.h" +#include "source/common/orca/orca_parser.h" #include "source/common/router/config_impl.h" #include "source/common/router/debug_config.h" #include "source/common/router/retry_state_impl.h" @@ -580,7 +582,11 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers, (upstream_http_protocol_options.value().auto_sni() || upstream_http_protocol_options.value().auto_san_validation())) { // Default the header to Host/Authority header. - absl::string_view header_value = headers.getHostValue(); + std::string header_value = route_entry_->getRequestHostValue(headers); + if (!Runtime::runtimeFeatureEnabled( + "envoy.reloadable_features.use_route_host_mutation_for_auto_sni_san")) { + header_value = std::string(headers.getHostValue()); + } // Check whether `override_auto_sni_header` is specified. const auto override_auto_sni_header = @@ -1564,6 +1570,8 @@ void Filter::onUpstreamHeaders(uint64_t response_code, Http::ResponseHeaderMapPt } } + maybeProcessOrcaLoadReport(*headers, upstream_request); + if (grpc_status.has_value()) { upstream_request.upstreamHost()->outlierDetector().putHttpResponseCode(grpc_to_http_status); } else { @@ -1733,6 +1741,8 @@ void Filter::onUpstreamTrailers(Http::ResponseTrailerMapPtr&& trailers, } } + maybeProcessOrcaLoadReport(*trailers, upstream_request); + onUpstreamComplete(upstream_request); callbacks_->encodeTrailers(std::move(trailers)); @@ -2096,6 +2106,38 @@ bool Filter::checkDropOverload(Upstream::ThreadLocalCluster& cluster, return false; } +void Filter::maybeProcessOrcaLoadReport(const Envoy::Http::HeaderMap& headers_or_trailers, + UpstreamRequest& upstream_request) { + // Process the load report only once, so if response has report in headers, + // then don't process it in trailers. + if (orca_load_report_received_) { + return; + } + // Check whether we need to send the load report to the LRS or invoke the ORCA + // callbacks. + auto host = upstream_request.upstreamHost(); + const bool need_to_send_load_report = + (host != nullptr) && cluster_->lrsReportMetricNames().has_value(); + if (!need_to_send_load_report) { + return; + } + + absl::StatusOr orca_load_report = + Envoy::Orca::parseOrcaLoadReportHeaders(headers_or_trailers); + if (!orca_load_report.ok()) { + ENVOY_STREAM_LOG(trace, "Headers don't have orca load report: {}", *callbacks_, + orca_load_report.status().message()); + return; + } + + orca_load_report_received_ = true; + + ENVOY_STREAM_LOG(trace, "Adding ORCA load report {} to load metrics", *callbacks_, + orca_load_report->DebugString()); + Envoy::Orca::addOrcaLoadReportToLoadMetricStats( + cluster_->lrsReportMetricNames().value(), orca_load_report.value(), host->loadMetricStats()); +} + RetryStatePtr ProdFilter::createRetryState(const RetryPolicy& policy, Http::RequestHeaderMap& request_headers, const Upstream::ClusterInfo& cluster, const VirtualCluster* vcluster, diff --git a/source/common/router/router.h b/source/common/router/router.h index 4b93247e29fd..6e92950fbe1d 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -308,7 +308,7 @@ class Filter : Logger::Loggable, downstream_response_started_(false), downstream_end_stream_(false), is_retry_(false), request_buffer_overflowed_(false), streaming_shadows_(Runtime::runtimeFeatureEnabled( "envoy.reloadable_features.streaming_shadow")), - upstream_request_started_(false) {} + upstream_request_started_(false), orca_load_report_received_(false) {} ~Filter() override; @@ -559,6 +559,9 @@ class Filter : Logger::Loggable, Http::Context& httpContext() { return config_->http_context_; } bool checkDropOverload(Upstream::ThreadLocalCluster& cluster, std::function& modify_headers); + // Process Orca Load Report if necessary (e.g. cluster has lrsReportMetricNames). + void maybeProcessOrcaLoadReport(const Envoy::Http::HeaderMap& headers_or_trailers, + UpstreamRequest& upstream_request); RetryStatePtr retry_state_; const FilterConfigSharedPtr config_; @@ -611,6 +614,9 @@ class Filter : Logger::Loggable, bool request_buffer_overflowed_ : 1; const bool streaming_shadows_ : 1; bool upstream_request_started_ : 1; + // Indicate that ORCA report is received to process it only once in either response headers or + // trailers. + bool orca_load_report_received_ : 1; }; class ProdFilter : public Filter { diff --git a/source/common/router/upstream_codec_filter.cc b/source/common/router/upstream_codec_filter.cc index 56ac395dd40b..846645a5e000 100644 --- a/source/common/router/upstream_codec_filter.cc +++ b/source/common/router/upstream_codec_filter.cc @@ -148,10 +148,7 @@ void UpstreamCodecFilter::CodecBridge::decodeHeaders(Http::ResponseHeaderMapPtr& filter_.callbacks_->dispatcher().timeSource()); if (filter_.callbacks_->upstreamCallbacks()->pausedForConnect() && - ((Http::Utility::getResponseStatus(*headers) == 200) || - ((Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.upstream_allow_connect_with_2xx")) && - (Http::CodeUtility::is2xx(Http::Utility::getResponseStatus(*headers)))))) { + ((Http::CodeUtility::is2xx(Http::Utility::getResponseStatus(*headers))))) { filter_.callbacks_->upstreamCallbacks()->setPausedForConnect(false); filter_.callbacks_->continueDecoding(); } diff --git a/source/common/router/upstream_request.cc b/source/common/router/upstream_request.cc index 18fb79901bec..b14ad939a6be 100644 --- a/source/common/router/upstream_request.cc +++ b/source/common/router/upstream_request.cc @@ -68,8 +68,8 @@ class UpstreamFilterManager : public Http::FilterManager { absl::string_view details) override { state().decoder_filter_chain_aborted_ = true; state().encoder_filter_chain_aborted_ = true; - state().remote_encode_complete_ = true; - state().local_complete_ = true; + state().encoder_filter_chain_complete_ = true; + state().observed_encode_end_stream_ = true; // TODO(alyssawilk) this should be done through the router to play well with hedging. upstream_request_.parent_.callbacks()->sendLocalReply(code, body, modify_headers, grpc_status, details); @@ -596,9 +596,6 @@ void UpstreamRequest::onPoolReady(std::unique_ptr&& upstream, had_upstream_ = true; // Have the upstream use the account of the downstream. upstream_->setAccount(parent_.callbacks()->account()); - if (enable_half_close_) { - upstream_->enableHalfClose(); - } host->outlierDetector().putResult(Upstream::Outlier::Result::LocalOriginConnectSuccess); diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index 55cf4e0e57d7..cff3db99a0bb 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -29,6 +29,7 @@ // If issues are found that require a runtime feature to be disabled, it should be reported // ASAP by filing a bug on github. Overriding non-buggy code is strongly discouraged to avoid the // problem of the bugs being found after the old code path has been removed. +RUNTIME_GUARD(envoy_reloadable_features_allow_alt_svc_for_ips); RUNTIME_GUARD(envoy_reloadable_features_check_switch_protocol_websocket_handshake); RUNTIME_GUARD(envoy_reloadable_features_conn_pool_delete_when_idle); RUNTIME_GUARD(envoy_reloadable_features_consistent_header_validation); @@ -44,11 +45,11 @@ RUNTIME_GUARD(envoy_reloadable_features_enable_compression_bomb_protection); RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms); RUNTIME_GUARD(envoy_reloadable_features_exclude_host_in_eds_status_draining); RUNTIME_GUARD(envoy_reloadable_features_ext_proc_timeout_error); +RUNTIME_GUARD(envoy_reloadable_features_extend_h3_accept_untrusted); RUNTIME_GUARD(envoy_reloadable_features_gcp_authn_use_fixed_url); RUNTIME_GUARD(envoy_reloadable_features_grpc_side_stream_flow_control); RUNTIME_GUARD(envoy_reloadable_features_http1_balsa_delay_reset); RUNTIME_GUARD(envoy_reloadable_features_http1_balsa_disallow_lone_cr_in_chunk_extension); -RUNTIME_GUARD(envoy_reloadable_features_http1_connection_close_header_in_redirect); // Ignore the automated "remove this flag" issue: we should keep this for 1 year. RUNTIME_GUARD(envoy_reloadable_features_http1_use_balsa_parser); RUNTIME_GUARD(envoy_reloadable_features_http2_discard_host_header); @@ -61,18 +62,16 @@ RUNTIME_GUARD(envoy_reloadable_features_http_filter_avoid_reentrant_local_reply) // Delay deprecation and decommission until UHV is enabled. RUNTIME_GUARD(envoy_reloadable_features_http_reject_path_with_fragment); RUNTIME_GUARD(envoy_reloadable_features_http_route_connect_proxy_by_default); +RUNTIME_GUARD(envoy_reloadable_features_internal_authority_header_validator); RUNTIME_GUARD(envoy_reloadable_features_jwt_authn_remove_jwt_from_query_params); RUNTIME_GUARD(envoy_reloadable_features_jwt_authn_validate_uri); RUNTIME_GUARD(envoy_reloadable_features_lua_flow_control_while_http_call); RUNTIME_GUARD(envoy_reloadable_features_no_extension_lookup_by_name); RUNTIME_GUARD(envoy_reloadable_features_no_timer_based_rate_limit_token_bucket); -RUNTIME_GUARD(envoy_reloadable_features_normalize_host_for_preresolve_dfp_dns); RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout); -// Fixes fail-open behaviour of failure_mode_allow for external authz grpc servers. -RUNTIME_GUARD(envoy_reloadable_features_process_ext_authz_grpc_error_codes_as_errors); +RUNTIME_GUARD(envoy_reloadable_features_prefer_ipv6_dns_on_macos); RUNTIME_GUARD(envoy_reloadable_features_proxy_104); RUNTIME_GUARD(envoy_reloadable_features_proxy_status_mapping_more_core_response_flags); -RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf); RUNTIME_GUARD(envoy_reloadable_features_quic_receive_ecn); // Ignore the automated "remove this flag" issue: we should keep this for 1 year. Confirm with // @danzh2010 or @RyanTheOptimist before removing. @@ -90,9 +89,10 @@ RUNTIME_GUARD(envoy_reloadable_features_tcp_tunneling_send_downstream_fin_on_ups RUNTIME_GUARD(envoy_reloadable_features_test_feature_true); RUNTIME_GUARD(envoy_reloadable_features_udp_socket_apply_aggregated_read_limit); RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding); -RUNTIME_GUARD(envoy_reloadable_features_upstream_allow_connect_with_2xx); RUNTIME_GUARD(envoy_reloadable_features_upstream_remote_address_use_connection); +RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs); RUNTIME_GUARD(envoy_reloadable_features_use_http3_header_normalisation); +RUNTIME_GUARD(envoy_reloadable_features_use_route_host_mutation_for_auto_sni_san); RUNTIME_GUARD(envoy_reloadable_features_use_typed_metadata_in_proxy_protocol_listener); RUNTIME_GUARD(envoy_reloadable_features_validate_connect); RUNTIME_GUARD(envoy_reloadable_features_validate_grpc_header_before_log_grpc_status); @@ -101,7 +101,7 @@ RUNTIME_GUARD(envoy_reloadable_features_xdstp_path_avoid_colon_encoding); RUNTIME_GUARD(envoy_restart_features_allow_client_socket_creation_failure); RUNTIME_GUARD(envoy_restart_features_allow_slot_destroy_on_worker_threads); RUNTIME_GUARD(envoy_restart_features_quic_handle_certs_with_shared_tls_code); -RUNTIME_GUARD(envoy_restart_features_udp_read_normalize_addresses); +RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads); RUNTIME_GUARD(envoy_restart_features_use_fast_protobuf_hash); // Begin false flags. Most of them should come with a TODO to flip true. @@ -131,16 +131,12 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all); // remove the feature flag and remove code path that relies on old technique to fetch credentials // via libcurl and remove the bazel steps to pull and test the curl dependency. FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials); -// TODO(adisuissa): enable by default once this is tested in prod. -FALSE_RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads); // TODO(#10646) change to true when UHV is sufficiently tested // For more information about Universal Header Validation, please see // https://github.com/envoyproxy/envoy/issues/10646 FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_universal_header_validator); // TODO(pksohn): enable after canarying fix for https://github.com/envoyproxy/envoy/issues/29930 FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_defer_logging_to_ack_listener); -// TODO(panting): flip this to true after some test time. -FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs); // TODO(#33474) removed it once GRO packet dropping is fixed. FALSE_RUNTIME_GUARD(envoy_reloadable_features_prefer_quic_client_udp_gro); // TODO(alyssar) evaluate and either make this a config knob or remove. @@ -151,6 +147,8 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_reresolve_if_no_connections); FALSE_RUNTIME_GUARD(envoy_restart_features_xds_failover_support); // TODO(fredyw): evaluate and either make this a config knob or remove. FALSE_RUNTIME_GUARD(envoy_reloadable_features_dns_cache_set_ip_version_to_remove); +// TODO(alyssawilk): evaluate and make this a config knob or remove. +FALSE_RUNTIME_GUARD(envoy_reloadable_features_reset_brokenness_on_nework_change); // A flag to set the maximum TLS version for google_grpc client to TLS1.2, when needed for // compliance restrictions. diff --git a/source/common/runtime/runtime_impl.cc b/source/common/runtime/runtime_impl.cc index e2a0619393e4..917ef6e655a1 100644 --- a/source/common/runtime/runtime_impl.cc +++ b/source/common/runtime/runtime_impl.cc @@ -439,9 +439,9 @@ absl::Status DiskLayer::walkDirectory(const std::string& path, const std::string Filesystem::Directory directory(path); Filesystem::DirectoryIteratorImpl it = directory.begin(); - RETURN_IF_STATUS_NOT_OK(it); + RETURN_IF_NOT_OK_REF(it.status()); for (; it != directory.end(); ++it) { - RETURN_IF_STATUS_NOT_OK(it); + RETURN_IF_NOT_OK_REF(it.status()); Filesystem::DirectoryEntry entry = *it; std::string full_path = path + "/" + entry.name_; std::string full_prefix; @@ -465,7 +465,7 @@ absl::Status DiskLayer::walkDirectory(const std::string& path, const std::string // Read the file and remove any comments. A comment is a line starting with a '#' character. // Comments are useful for placeholder files with no value. auto file_or_error = api.fileSystem().fileReadToEnd(full_path); - RETURN_IF_STATUS_NOT_OK(file_or_error); + RETURN_IF_NOT_OK_REF(file_or_error.status()); const std::string text_file{file_or_error.value()}; const auto lines = StringUtil::splitToken(text_file, "\n"); @@ -492,7 +492,7 @@ absl::Status DiskLayer::walkDirectory(const std::string& path, const std::string #endif } } - RETURN_IF_STATUS_NOT_OK(it); + RETURN_IF_NOT_OK_REF(it.status()); return absl::OkStatus(); } @@ -721,7 +721,7 @@ absl::Status RtdsSubscription::onConfigRemoved( absl::Status LoaderImpl::loadNewSnapshot() { auto snapshot_or_error = createNewSnapshot(); - RETURN_IF_STATUS_NOT_OK(snapshot_or_error); + RETURN_IF_NOT_OK_REF(snapshot_or_error.status()); std::shared_ptr ptr = std::move(snapshot_or_error.value()); tls_->set([ptr](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { return std::static_pointer_cast(ptr); diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index a8ab37af3ee6..620bffb4972d 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -126,7 +126,7 @@ absl::Status SdsApi::onConfigUpdate(const std::vectoraddWatch(absl::StrCat(result_or_error.value().directory_, "/"), Filesystem::Watcher::Events::MovedTo, [this](uint32_t) { diff --git a/source/common/stats/tag_producer_impl.cc b/source/common/stats/tag_producer_impl.cc index e01fd800f668..082f98a722bf 100644 --- a/source/common/stats/tag_producer_impl.cc +++ b/source/common/stats/tag_producer_impl.cc @@ -158,7 +158,7 @@ TagProducerImpl::addDefaultExtractors(const envoy::config::metrics::v3::StatsCon for (const auto& desc : Config::TagNames::get().descriptorVec()) { auto extractor_or_error = TagExtractorImplBase::createTagExtractor( desc.name_, desc.regex_, desc.substr_, desc.negative_match_, desc.re_type_); - RETURN_IF_STATUS_NOT_OK(extractor_or_error); + RETURN_IF_NOT_OK_REF(extractor_or_error.status()); addExtractor(std::move(extractor_or_error.value())); } for (const auto& desc : Config::TagNames::get().tokenizedDescriptorVec()) { diff --git a/source/common/stream_info/stream_info_impl.h b/source/common/stream_info/stream_info_impl.h index 15a6e46eccc4..f74ad7cdd406 100644 --- a/source/common/stream_info/stream_info_impl.h +++ b/source/common/stream_info/stream_info_impl.h @@ -377,10 +377,7 @@ struct StreamInfoImpl : public StreamInfo { downstream_transport_failure_reason_ = std::string(info.downstreamTransportFailureReason()); bytes_retransmitted_ = info.bytesRetransmitted(); packets_retransmitted_ = info.packetsRetransmitted(); - if (Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.http1_connection_close_header_in_redirect")) { - should_drain_connection_ = info.shouldDrainConnectionUponCompletion(); - } + should_drain_connection_ = info.shouldDrainConnectionUponCompletion(); } // This function is used to copy over every field exposed in the StreamInfo interface, with a @@ -419,6 +416,7 @@ struct StreamInfoImpl : public StreamInfo { upstream_bytes_meter_ = info.getUpstreamBytesMeter(); bytes_sent_ = info.bytesSent(); is_shadow_ = info.isShadow(); + parent_stream_info_ = info.parentStreamInfo(); } void setIsShadow(bool is_shadow) { is_shadow_ = is_shadow; } @@ -444,6 +442,14 @@ struct StreamInfoImpl : public StreamInfo { should_drain_connection_ = should_drain; } + void setParentStreamInfo(const StreamInfo& parent_stream_info) override { + parent_stream_info_ = parent_stream_info; + } + + OptRef parentStreamInfo() const override { return parent_stream_info_; } + + void clearParentStreamInfo() override { parent_stream_info_.reset(); } + TimeSource& time_source_; SystemTime start_time_; MonotonicTime start_time_monotonic_; @@ -492,6 +498,7 @@ struct StreamInfoImpl : public StreamInfo { std::string downstream_transport_failure_reason_; bool should_scheme_match_upstream_{false}; bool should_drain_connection_{false}; + OptRef parent_stream_info_; }; } // namespace StreamInfo diff --git a/source/common/tcp/async_tcp_client_impl.cc b/source/common/tcp/async_tcp_client_impl.cc index 4d6482cb5dc6..0d6ce288c8ed 100644 --- a/source/common/tcp/async_tcp_client_impl.cc +++ b/source/common/tcp/async_tcp_client_impl.cc @@ -24,6 +24,14 @@ AsyncTcpClientImpl::AsyncTcpClientImpl(Event::Dispatcher& dispatcher, connect_timer_(dispatcher.createTimer([this]() { onConnectTimeout(); })), enable_half_close_(enable_half_close) {} +AsyncTcpClientImpl::~AsyncTcpClientImpl() { + if (connection_) { + connection_->removeConnectionCallbacks(*this); + } + + close(Network::ConnectionCloseType::NoFlush); +} + bool AsyncTcpClientImpl::connect() { if (connection_) { return false; @@ -69,7 +77,8 @@ void AsyncTcpClientImpl::onConnectTimeout() { } void AsyncTcpClientImpl::close(Network::ConnectionCloseType type) { - if (connection_) { + if (connection_ && !closing_) { + closing_ = true; connection_->close(type); } } @@ -127,6 +136,7 @@ void AsyncTcpClientImpl::onEvent(Network::ConnectionEvent event) { detected_close_ = connection_->detectedCloseType(); } + closing_ = false; dispatcher_.deferredDelete(std::move(connection_)); if (callbacks_) { callbacks_->onEvent(event); diff --git a/source/common/tcp/async_tcp_client_impl.h b/source/common/tcp/async_tcp_client_impl.h index ef965ca68cc5..2f239b757028 100644 --- a/source/common/tcp/async_tcp_client_impl.h +++ b/source/common/tcp/async_tcp_client_impl.h @@ -28,6 +28,7 @@ class AsyncTcpClientImpl : public AsyncTcpClient, AsyncTcpClientImpl(Event::Dispatcher& dispatcher, Upstream::ThreadLocalCluster& thread_local_cluster, Upstream::LoadBalancerContext* context, bool enable_half_close); + ~AsyncTcpClientImpl(); void close(Network::ConnectionCloseType type) override; @@ -106,6 +107,7 @@ class AsyncTcpClientImpl : public AsyncTcpClient, Event::TimerPtr connect_timer_; AsyncTcpClientCallbacks* callbacks_{}; Network::DetectedCloseType detected_close_{Network::DetectedCloseType::Normal}; + bool closing_{false}; bool connected_{false}; bool enable_half_close_{false}; }; diff --git a/source/common/tcp_proxy/upstream.h b/source/common/tcp_proxy/upstream.h index 1f2135b40532..7aae5ebb47d2 100644 --- a/source/common/tcp_proxy/upstream.h +++ b/source/common/tcp_proxy/upstream.h @@ -59,6 +59,23 @@ class TcpConnPool : public GenericConnPool, public Tcp::ConnectionPool::Callback class HttpUpstream; class CombinedUpstream; +// This class is specific to TCP proxy connection pool and enables TCP proxying mode +// for HTTP upstreams. This is currently only needed for HTTP/1 client codec that half closes +// upstream network connection after encoding end_stream in TCP proxy (i.e. via CONNECT). +class RouterUpstreamRequest : public Router::UpstreamRequest { +public: + using Router::UpstreamRequest::UpstreamRequest; + + void onPoolReady(std::unique_ptr&& upstream, + Upstream::HostDescriptionConstSharedPtr host, + const Network::ConnectionInfoProvider& address_provider, + StreamInfo::StreamInfo& info, absl::optional protocol) override { + upstream->enableTcpTunneling(); + Router::UpstreamRequest::onPoolReady(std::move(upstream), host, address_provider, info, + protocol); + } +}; + class HttpConnPool : public GenericConnPool, public Http::ConnectionPool::Callbacks { public: HttpConnPool(Upstream::ThreadLocalCluster& thread_local_cluster, @@ -67,7 +84,6 @@ class HttpConnPool : public GenericConnPool, public Http::ConnectionPool::Callba Http::StreamDecoderFilterCallbacks&, Http::CodecType type, StreamInfo::StreamInfo& downstream_info); - using RouterUpstreamRequest = Router::UpstreamRequest; using RouterUpstreamRequestPtr = std::unique_ptr; ~HttpConnPool() override; diff --git a/source/common/tls/connection_info_impl_base.cc b/source/common/tls/connection_info_impl_base.cc index 5ae15002163d..af03e2cc6853 100644 --- a/source/common/tls/connection_info_impl_base.cc +++ b/source/common/tls/connection_info_impl_base.cc @@ -1,10 +1,14 @@ #include "source/common/tls/connection_info_impl_base.h" +#include + #include "source/common/common/hex.h" #include "absl/strings/str_replace.h" #include "openssl/err.h" +#include "openssl/safestack.h" #include "openssl/x509v3.h" +#include "utility.h" namespace Envoy { namespace Extensions { @@ -77,6 +81,29 @@ const std::string& ConnectionInfoImplBase::sha256PeerCertificateDigest() const { return cached_sha_256_peer_certificate_digest_; } +absl::Span ConnectionInfoImplBase::sha256PeerCertificateChainDigests() const { + if (!cached_sha_256_peer_certificate_digests_.empty()) { + return cached_sha_256_peer_certificate_digests_; + } + + STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl()); + if (cert_chain == nullptr) { + ASSERT(cached_sha_256_peer_certificate_digests_.empty()); + return cached_sha_256_peer_certificate_digests_; + } + + cached_sha_256_peer_certificate_digests_ = + Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string { + std::vector computed_hash(SHA256_DIGEST_LENGTH); + unsigned int n; + X509_digest(&cert, EVP_sha256(), computed_hash.data(), &n); + RELEASE_ASSERT(n == computed_hash.size(), ""); + return Hex::encode(computed_hash); + }); + + return cached_sha_256_peer_certificate_digests_; +} + const std::string& ConnectionInfoImplBase::sha1PeerCertificateDigest() const { if (!cached_sha_1_peer_certificate_digest_.empty()) { return cached_sha_1_peer_certificate_digest_; @@ -95,6 +122,29 @@ const std::string& ConnectionInfoImplBase::sha1PeerCertificateDigest() const { return cached_sha_1_peer_certificate_digest_; } +absl::Span ConnectionInfoImplBase::sha1PeerCertificateChainDigests() const { + if (!cached_sha_1_peer_certificate_digests_.empty()) { + return cached_sha_1_peer_certificate_digests_; + } + + STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl()); + if (cert_chain == nullptr) { + ASSERT(cached_sha_1_peer_certificate_digests_.empty()); + return cached_sha_1_peer_certificate_digests_; + } + + cached_sha_1_peer_certificate_digests_ = + Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string { + std::vector computed_hash(SHA_DIGEST_LENGTH); + unsigned int n; + X509_digest(&cert, EVP_sha1(), computed_hash.data(), &n); + RELEASE_ASSERT(n == computed_hash.size(), ""); + return Hex::encode(computed_hash); + }); + + return cached_sha_1_peer_certificate_digests_; +} + const std::string& ConnectionInfoImplBase::urlEncodedPemEncodedPeerCertificate() const { if (!cached_url_encoded_pem_encoded_peer_certificate_.empty()) { return cached_url_encoded_pem_encoded_peer_certificate_; @@ -253,6 +303,25 @@ const std::string& ConnectionInfoImplBase::serialNumberPeerCertificate() const { return cached_serial_number_peer_certificate_; } +absl::Span ConnectionInfoImplBase::serialNumbersPeerCertificates() const { + if (!cached_serial_numbers_peer_certificates_.empty()) { + return cached_serial_numbers_peer_certificates_; + } + + STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl()); + if (cert_chain == nullptr) { + ASSERT(cached_serial_numbers_peer_certificates_.empty()); + return cached_serial_numbers_peer_certificates_; + } + + cached_serial_numbers_peer_certificates_ = + Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string { + return Utility::getSerialNumberFromCertificate(cert); + }); + + return cached_serial_numbers_peer_certificates_; +} + const std::string& ConnectionInfoImplBase::issuerPeerCertificate() const { if (!cached_issuer_peer_certificate_.empty()) { return cached_issuer_peer_certificate_; diff --git a/source/common/tls/connection_info_impl_base.h b/source/common/tls/connection_info_impl_base.h index 8bcacdb80f7f..475fa21b6d0c 100644 --- a/source/common/tls/connection_info_impl_base.h +++ b/source/common/tls/connection_info_impl_base.h @@ -22,8 +22,11 @@ class ConnectionInfoImplBase : public Ssl::ConnectionInfo { bool peerCertificatePresented() const override; absl::Span uriSanLocalCertificate() const override; const std::string& sha256PeerCertificateDigest() const override; + absl::Span sha256PeerCertificateChainDigests() const override; const std::string& sha1PeerCertificateDigest() const override; + absl::Span sha1PeerCertificateChainDigests() const override; const std::string& serialNumberPeerCertificate() const override; + absl::Span serialNumbersPeerCertificates() const override; const std::string& issuerPeerCertificate() const override; const std::string& subjectPeerCertificate() const override; const std::string& subjectLocalCertificate() const override; @@ -48,8 +51,11 @@ class ConnectionInfoImplBase : public Ssl::ConnectionInfo { protected: mutable std::vector cached_uri_san_local_certificate_; mutable std::string cached_sha_256_peer_certificate_digest_; + mutable std::vector cached_sha_256_peer_certificate_digests_; mutable std::string cached_sha_1_peer_certificate_digest_; + mutable std::vector cached_sha_1_peer_certificate_digests_; mutable std::string cached_serial_number_peer_certificate_; + mutable std::vector cached_serial_numbers_peer_certificates_; mutable std::string cached_issuer_peer_certificate_; mutable std::string cached_subject_peer_certificate_; mutable std::string cached_subject_local_certificate_; diff --git a/source/common/tls/ocsp/ocsp.cc b/source/common/tls/ocsp/ocsp.cc index b6b52eda7649..51ef8566a6b1 100644 --- a/source/common/tls/ocsp/ocsp.cc +++ b/source/common/tls/ocsp/ocsp.cc @@ -45,9 +45,9 @@ absl::Status skipResponderId(CBS& cbs) { // (excluding the tag and length fields) auto opt1 = Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1); - RETURN_IF_STATUS_NOT_OK(opt1); + RETURN_IF_NOT_OK_REF(opt1.status()); auto opt2 = Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2); - RETURN_IF_STATUS_NOT_OK(opt2); + RETURN_IF_NOT_OK_REF(opt2.status()); if (opt1.value() || opt2.value()) { return absl::OkStatus(); @@ -64,11 +64,11 @@ absl::Status skipCertStatus(CBS& cbs) { // unknown [2] IMPLICIT UnknownInfo // } auto opt1 = Asn1Utility::getOptional(cbs, CBS_ASN1_CONTEXT_SPECIFIC | 0); - RETURN_IF_STATUS_NOT_OK(opt1); + RETURN_IF_NOT_OK_REF(opt1.status()); auto opt2 = Asn1Utility::getOptional(cbs, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1); - RETURN_IF_STATUS_NOT_OK(opt2); + RETURN_IF_NOT_OK_REF(opt2.status()); auto opt3 = Asn1Utility::getOptional(cbs, CBS_ASN1_CONTEXT_SPECIFIC | 2); - RETURN_IF_STATUS_NOT_OK(opt3); + RETURN_IF_NOT_OK_REF(opt3.status()); if (!(opt1.value() || opt2.value() || opt3.value())) { return absl::InvalidArgumentError( @@ -181,14 +181,14 @@ absl::StatusOr> Asn1OcspUtility::parseOcspResponse } auto status_or_error = Asn1OcspUtility::parseResponseStatus(elem); - RETURN_IF_STATUS_NOT_OK(status_or_error); + RETURN_IF_NOT_OK_REF(status_or_error.status()); auto opt = Asn1Utility::getOptional(elem, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0); - RETURN_IF_STATUS_NOT_OK(opt); + RETURN_IF_NOT_OK_REF(opt.status()); auto maybe_bytes = opt.value(); ResponsePtr resp = nullptr; if (maybe_bytes) { auto resp_or_error = Asn1OcspUtility::parseResponseBytes(maybe_bytes.value()); - RETURN_IF_STATUS_NOT_OK(resp_or_error); + RETURN_IF_NOT_OK_REF(resp_or_error.status()); resp = std::move(resp_or_error.value()); } @@ -243,7 +243,7 @@ absl::StatusOr Asn1OcspUtility::parseResponseBytes(CBS& cbs) { } auto parse_or_error = Asn1Utility::parseOid(elem); - RETURN_IF_STATUS_NOT_OK(parse_or_error); + RETURN_IF_NOT_OK_REF(parse_or_error.status()); auto oid_str = parse_or_error.value(); if (!CBS_get_asn1(&elem, &response, CBS_ASN1_OCTETSTRING)) { return absl::InvalidArgumentError("Expected ASN.1 OCTETSTRING for response"); @@ -271,7 +271,7 @@ Asn1OcspUtility::parseBasicOcspResponse(CBS& cbs) { "OCSP BasicOCSPResponse is not a wellf-formed ASN.1 SEQUENCE"); } auto response_or_error = Asn1OcspUtility::parseResponseData(elem); - RETURN_IF_STATUS_NOT_OK(response_or_error); + RETURN_IF_NOT_OK_REF(response_or_error.status()); // The `signatureAlgorithm` and `signature` are ignored because OCSP // responses are expected to be delivered from a reliable source. // Optional additional certs are ignored. @@ -295,11 +295,11 @@ absl::StatusOr Asn1OcspUtility::parseResponseData(CBS& cbs) { // only support v1, the value of v1 is 0x00 auto version_or_error = Asn1Utility::getOptional(elem, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0); - RETURN_IF_STATUS_NOT_OK(version_or_error); + RETURN_IF_NOT_OK_REF(version_or_error.status()); auto version_cbs = version_or_error.value(); if (version_cbs.has_value()) { auto version_or_error = Asn1Utility::parseInteger(*version_cbs); - RETURN_IF_STATUS_NOT_OK(version_or_error); + RETURN_IF_NOT_OK_REF(version_or_error.status()); auto version = version_or_error.value(); if (version != "00") { return absl::InvalidArgumentError( @@ -309,10 +309,10 @@ absl::StatusOr Asn1OcspUtility::parseResponseData(CBS& cbs) { auto status = skipResponderId(elem); RETURN_IF_NOT_OK(status); - RETURN_IF_STATUS_NOT_OK(Asn1Utility::skip(elem, CBS_ASN1_GENERALIZEDTIME)); + RETURN_IF_NOT_OK_REF(Asn1Utility::skip(elem, CBS_ASN1_GENERALIZEDTIME).status()); auto responses_or_error = Asn1Utility::parseSequenceOf( elem, [](CBS& cbs) -> absl::StatusOr { return {parseSingleResponse(cbs)}; }); - RETURN_IF_STATUS_NOT_OK(responses_or_error); + RETURN_IF_NOT_OK_REF(responses_or_error.status()); // Extensions currently ignored. return {std::move(responses_or_error.value())}; @@ -332,14 +332,14 @@ absl::StatusOr Asn1OcspUtility::parseSingleResponse(CBS& cbs) { } auto id_or_error = Asn1OcspUtility::parseCertId(elem); - RETURN_IF_STATUS_NOT_OK(id_or_error); + RETURN_IF_NOT_OK_REF(id_or_error.status()); RETURN_IF_NOT_OK(skipCertStatus(elem)); auto this_update_or_error = Asn1Utility::parseGeneralizedTime(elem); - RETURN_IF_STATUS_NOT_OK(this_update_or_error); + RETURN_IF_NOT_OK_REF(this_update_or_error.status()); auto next_update_or_error = Asn1Utility::parseOptional( elem, Asn1Utility::parseGeneralizedTime, CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0); - RETURN_IF_STATUS_NOT_OK(next_update_or_error); + RETURN_IF_NOT_OK_REF(next_update_or_error.status()); // Extensions currently ignored. return SingleResponse{id_or_error.value(), this_update_or_error.value(), @@ -358,11 +358,11 @@ absl::StatusOr Asn1OcspUtility::parseCertId(CBS& cbs) { return absl::InvalidArgumentError("OCSP CertID is not a well-formed ASN.1 SEQUENCE"); } - RETURN_IF_STATUS_NOT_OK(Asn1Utility::skip(elem, CBS_ASN1_SEQUENCE)); - RETURN_IF_STATUS_NOT_OK(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING)); - RETURN_IF_STATUS_NOT_OK(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING)); + RETURN_IF_NOT_OK_REF(Asn1Utility::skip(elem, CBS_ASN1_SEQUENCE).status()); + RETURN_IF_NOT_OK_REF(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING).status()); + RETURN_IF_NOT_OK_REF(Asn1Utility::skip(elem, CBS_ASN1_OCTETSTRING).status()); auto serial_number_or_error = Asn1Utility::parseInteger(elem); - RETURN_IF_STATUS_NOT_OK(serial_number_or_error); + RETURN_IF_NOT_OK_REF(serial_number_or_error.status()); return {serial_number_or_error.value()}; } diff --git a/source/common/tls/utility.cc b/source/common/tls/utility.cc index 6df4276a4e99..619f5da999e6 100644 --- a/source/common/tls/utility.cc +++ b/source/common/tls/utility.cc @@ -1,6 +1,7 @@ #include "source/common/tls/utility.h" #include +#include #include "source/common/common/assert.h" #include "source/common/common/empty_string.h" @@ -463,6 +464,30 @@ std::string Utility::getX509VerificationErrorInfo(X509_STORE_CTX* ctx) { return error_details; } +std::vector Utility::mapX509Stack(stack_st_X509& stack, + std::function field_extractor) { + std::vector result; + if (sk_X509_num(&stack) <= 0) { + IS_ENVOY_BUG("x509 stack is empty or NULL"); + return result; + } + if (field_extractor == nullptr) { + IS_ENVOY_BUG("field_extractor is nullptr"); + return result; + } + + for (uint64_t i = 0; i < sk_X509_num(&stack); i++) { + X509* cert = sk_X509_value(&stack, i); + if (!cert) { + result.push_back(""); // Add an empty string so it's clear something was omitted. + } else { + result.push_back(field_extractor(*cert)); + } + } + + return result; +} + } // namespace Tls } // namespace TransportSockets } // namespace Extensions diff --git a/source/common/tls/utility.h b/source/common/tls/utility.h index da9be3441174..4123e860bd34 100644 --- a/source/common/tls/utility.h +++ b/source/common/tls/utility.h @@ -48,6 +48,15 @@ bool labelWildcardMatch(absl::string_view dns_label, absl::string_view pattern); */ std::string getSerialNumberFromCertificate(X509& cert); +/** + * Maps a stack of x509 certificates to a vector of strings extracted from the certificates. + * @param stack the stack of certificates + * @param field_extractor the function to extract the field from each certificate. + * @return std::vector returns the list of fields extracted from the certificates. + */ +std::vector mapX509Stack(stack_st_X509& stack, + std::function field_extractor); + /** * Retrieves the subject alternate names of a certificate. * @param cert the certificate diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index 1def579c48c7..011eec2f43a1 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -457,6 +457,7 @@ envoy_cc_library( "//source/common/http/http2:codec_stats_lib", "//source/common/http/http3:codec_stats_lib", "//source/common/init:manager_lib", + "//source/common/orca:orca_load_metrics_lib", "//source/common/shared_pool:shared_pool_lib", "//source/common/stats:deferred_creation", "//source/common/stats:isolated_store_lib", diff --git a/source/common/upstream/cluster_factory_impl.cc b/source/common/upstream/cluster_factory_impl.cc index 1897c7f3b1bb..a4324b8d472d 100644 --- a/source/common/upstream/cluster_factory_impl.cc +++ b/source/common/upstream/cluster_factory_impl.cc @@ -97,7 +97,7 @@ ClusterFactoryImplBase::create(const envoy::config::cluster::v3::Cluster& cluste absl::StatusOr> status_or_cluster = createClusterImpl(cluster, context); - RETURN_IF_STATUS_NOT_OK(status_or_cluster); + RETURN_IF_NOT_OK_REF(status_or_cluster.status()); std::pair& new_cluster_pair = status_or_cluster.value(); @@ -110,7 +110,7 @@ ClusterFactoryImplBase::create(const envoy::config::cluster::v3::Cluster& cluste } else { auto checker_or_error = HealthCheckerFactory::create(cluster.health_checks()[0], *new_cluster_pair.first, server_context); - RETURN_IF_STATUS_NOT_OK(checker_or_error); + RETURN_IF_NOT_OK_REF(checker_or_error.status()); new_cluster_pair.first->setHealthChecker(checker_or_error.value()); } } @@ -119,7 +119,7 @@ ClusterFactoryImplBase::create(const envoy::config::cluster::v3::Cluster& cluste *new_cluster_pair.first, cluster, server_context.mainThreadDispatcher(), server_context.runtime(), context.outlierEventLogger(), server_context.api().randomGenerator()); - RETURN_IF_STATUS_NOT_OK(detector_or_error); + RETURN_IF_NOT_OK_REF(detector_or_error.status()); new_cluster_pair.first->setOutlierDetector(detector_or_error.value()); return status_or_cluster; diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index d62f54f9ec29..c0e8f515788b 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -417,7 +417,7 @@ ClusterManagerImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bo auto status_or_cluster = loadCluster(cluster, MessageUtil::hash(cluster), "", /*added_via_api=*/false, required_for_ads, active_clusters_); - RETURN_IF_STATUS_NOT_OK(status_or_cluster); + RETURN_IF_NOT_OK_REF(status_or_cluster.status()); } } @@ -437,7 +437,7 @@ ClusterManagerImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bo dyn_resources.ads_config(), random_, Envoy::Config::SubscriptionFactory::RetryInitialDelayMs, Envoy::Config::SubscriptionFactory::RetryMaxDelayMs); - RETURN_IF_STATUS_NOT_OK(strategy_or_error); + RETURN_IF_NOT_OK_REF(strategy_or_error.status()); JitteredExponentialBackOffStrategyPtr backoff_strategy = std::move(strategy_or_error.value()); const bool use_eds_cache = @@ -458,12 +458,12 @@ ClusterManagerImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bo } auto factory_primary_or_error = Config::Utility::factoryForGrpcApiConfigSource( *async_client_manager_, dyn_resources.ads_config(), *stats_.rootScope(), false, 0); - RETURN_IF_STATUS_NOT_OK(factory_primary_or_error); + RETURN_IF_NOT_OK_REF(factory_primary_or_error.status()); Grpc::AsyncClientFactoryPtr factory_failover = nullptr; if (Runtime::runtimeFeatureEnabled("envoy.restart_features.xds_failover_support")) { auto factory_failover_or_error = Config::Utility::factoryForGrpcApiConfigSource( *async_client_manager_, dyn_resources.ads_config(), *stats_.rootScope(), false, 1); - RETURN_IF_STATUS_NOT_OK(factory_failover_or_error); + RETURN_IF_NOT_OK_REF(factory_failover_or_error.status()); factory_failover = std::move(factory_failover_or_error.value()); } ads_mux_ = factory->create( @@ -489,12 +489,12 @@ ClusterManagerImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bo } auto factory_primary_or_error = Config::Utility::factoryForGrpcApiConfigSource( *async_client_manager_, dyn_resources.ads_config(), *stats_.rootScope(), false, 0); - RETURN_IF_STATUS_NOT_OK(factory_primary_or_error); + RETURN_IF_NOT_OK_REF(factory_primary_or_error.status()); Grpc::AsyncClientFactoryPtr factory_failover = nullptr; if (Runtime::runtimeFeatureEnabled("envoy.restart_features.xds_failover_support")) { auto factory_failover_or_error = Config::Utility::factoryForGrpcApiConfigSource( *async_client_manager_, dyn_resources.ads_config(), *stats_.rootScope(), false, 1); - RETURN_IF_STATUS_NOT_OK(factory_failover_or_error); + RETURN_IF_NOT_OK_REF(factory_failover_or_error.status()); factory_failover = std::move(factory_failover_or_error.value()); } ads_mux_ = factory->create( @@ -553,7 +553,7 @@ ClusterManagerImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bo if (!dyn_resources.cds_resources_locator().empty()) { auto url_or_error = Config::XdsResourceIdentifier::decodeUrl(dyn_resources.cds_resources_locator()); - RETURN_IF_STATUS_NOT_OK(url_or_error); + RETURN_IF_NOT_OK_REF(url_or_error.status()); cds_resources_locator = std::make_unique(std::move(url_or_error.value())); } @@ -594,7 +594,7 @@ absl::Status ClusterManagerImpl::initializeSecondaryClusters( RETURN_IF_NOT_OK(status); auto factory_or_error = Config::Utility::factoryForGrpcApiConfigSource( *async_client_manager_, load_stats_config, *stats_.rootScope(), false, 0); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); load_stats_reporter_ = std::make_unique( local_info_, *this, *stats_.rootScope(), factory_or_error.value()->createUncachedRawAsyncClient(), dispatcher_); diff --git a/source/common/upstream/health_discovery_service.cc b/source/common/upstream/health_discovery_service.cc index 1ef4adfc54c6..b1b219263584 100644 --- a/source/common/upstream/health_discovery_service.cc +++ b/source/common/upstream/health_discovery_service.cc @@ -440,7 +440,7 @@ absl::Status HdsCluster::updateHealthchecks( // If it does not, create a new one. auto checker_or_error = Upstream::HealthCheckerFactory::create(health_check, *this, server_context_); - RETURN_IF_STATUS_NOT_OK(checker_or_error); + RETURN_IF_NOT_OK_REF(checker_or_error.status()); auto new_health_checker = checker_or_error.value(); health_checkers_map.insert({health_check, new_health_checker}); health_checkers.push_back(new_health_checker); diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index f3d2066aed66..3b75fb478f5c 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -42,6 +42,7 @@ #include "source/common/http/http2/codec_stats.h" #include "source/common/http/utility.h" #include "source/common/network/address_impl.h" +#include "source/common/network/filter_state_proxy_info.h" #include "source/common/network/happy_eyeballs_connection_impl.h" #include "source/common/network/resolver_impl.h" #include "source/common/network/socket_option_factory.h" @@ -124,7 +125,7 @@ parseExtensionProtocolOptions( for (const auto& it : config.typed_extension_protocol_options()) { auto& name = it.first; auto object_or_error = createProtocolOptionsConfig(name, it.second, factory_context); - RETURN_IF_STATUS_NOT_OK(object_or_error); + RETURN_IF_NOT_OK_REF(object_or_error.status()); if (object_or_error.value() != nullptr) { options[name] = std::move(object_or_error.value()); } @@ -235,7 +236,7 @@ parseBindConfig(::Envoy::OptRef bind_ auto address_or_error = ::Envoy::Network::Address::resolveProtoSocketAddress(bind_config->source_address()); - RETURN_IF_STATUS_NOT_OK(address_or_error); + RETURN_IF_NOT_OK_REF(address_or_error.status()); upstream_local_address.address_ = address_or_error.value(); } upstream_local_address.socket_options_ = std::make_shared(); @@ -251,7 +252,7 @@ parseBindConfig(::Envoy::OptRef bind_ UpstreamLocalAddress extra_upstream_local_address; auto address_or_error = ::Envoy::Network::Address::resolveProtoSocketAddress(extra_source_address.address()); - RETURN_IF_STATUS_NOT_OK(address_or_error); + RETURN_IF_NOT_OK_REF(address_or_error.status()); extra_upstream_local_address.address_ = address_or_error.value(); extra_upstream_local_address.socket_options_ = @@ -275,7 +276,7 @@ parseBindConfig(::Envoy::OptRef bind_ UpstreamLocalAddress additional_upstream_local_address; auto address_or_error = ::Envoy::Network::Address::resolveProtoSocketAddress(additional_source_address); - RETURN_IF_STATUS_NOT_OK(address_or_error); + RETURN_IF_NOT_OK_REF(address_or_error.status()); additional_upstream_local_address.address_ = address_or_error.value(); additional_upstream_local_address.socket_options_ = std::make_shared<::Envoy::Network::ConnectionSocket::Options>(); @@ -373,13 +374,27 @@ createUpstreamLocalAddressSelector( envoy::config::core::v3::BindConfig{})), buildClusterSocketOptions(cluster_config, bootstrap_bind_config.value_or( envoy::config::core::v3::BindConfig{}))); - RETURN_IF_STATUS_NOT_OK(config_or_error); + RETURN_IF_NOT_OK_REF(config_or_error.status()); auto selector_or_error = local_address_selector_factory->createLocalAddressSelector( config_or_error.value(), cluster_name); - RETURN_IF_STATUS_NOT_OK(selector_or_error); + RETURN_IF_NOT_OK_REF(selector_or_error.status()); return selector_or_error.value(); } +class LoadBalancerFactoryContextImpl : public Upstream::LoadBalancerFactoryContext { +public: + explicit LoadBalancerFactoryContextImpl( + Server::Configuration::ServerFactoryContext& server_context) + : server_context_(server_context) {} + + Event::Dispatcher& mainThreadDispatcher() override { + return server_context_.mainThreadDispatcher(); + } + +private: + Server::Configuration::ServerFactoryContext& server_context_; +}; + } // namespace // Allow disabling ALPN checks for transport sockets. See @@ -521,6 +536,54 @@ Host::CreateConnectionData HostImplBase::createHealthCheckConnection( transport_socket_options, shared_from_this()); } +absl::optional HostImplBase::maybeGetProxyRedirectAddress( + const Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + HostDescriptionConstSharedPtr host) { + if (transport_socket_options && transport_socket_options->http11ProxyInfo().has_value()) { + return transport_socket_options->http11ProxyInfo()->proxy_address; + } + + // See if host metadata contains a proxy address and only check locality metadata if host + // metadata did not have the relevant key. + for (const auto& metadata : {host->metadata(), host->localityMetadata()}) { + if (metadata == nullptr) { + continue; + } + + auto addr_it = metadata->typed_filter_metadata().find( + Config::MetadataFilters::get().ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR); + if (addr_it == metadata->typed_filter_metadata().end()) { + continue; + } + + // Parse an address from the metadata. + envoy::config::core::v3::Address proxy_addr; + auto status = MessageUtil::unpackTo(addr_it->second, proxy_addr); + if (!status.ok()) { + ENVOY_LOG_EVERY_POW_2( + error, "failed to parse proto from endpoint/locality metadata field {}, host={}", + Config::MetadataFilters::get().ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR, + host->hostname()); + return absl::nullopt; + } + + // Resolve the parsed address proto. + auto resolve_status = Network::Address::resolveProtoAddress(proxy_addr); + if (!resolve_status.ok()) { + ENVOY_LOG_EVERY_POW_2( + error, "failed to resolve address from endpoint/locality metadata field {}, host={}", + Config::MetadataFilters::get().ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR, + host->hostname()); + return absl::nullopt; + } + + // We successfully resolved, so return the instance ptr. + return resolve_status.value(); + } + + return absl::nullopt; +} + Host::CreateConnectionData HostImplBase::createConnection( Event::Dispatcher& dispatcher, const ClusterInfo& cluster, const Network::Address::InstanceConstSharedPtr& address, @@ -531,17 +594,20 @@ Host::CreateConnectionData HostImplBase::createConnection( HostDescriptionConstSharedPtr host) { auto source_address_selector = cluster.getUpstreamLocalAddressSelector(); + absl::optional proxy_address = + maybeGetProxyRedirectAddress(transport_socket_options, host); + Network::ClientConnectionPtr connection; - // If the transport socket options indicate the connection should be - // redirected to a proxy, create the TCP connection to the proxy's address not - // the host's address. - if (transport_socket_options && transport_socket_options->http11ProxyInfo().has_value()) { + // If the transport socket options or endpoint/locality metadata indicate the connection should + // be redirected to a proxy, create the TCP connection to the proxy's address not the host's + // address. + if (proxy_address.has_value()) { auto upstream_local_address = source_address_selector->getUpstreamLocalAddress(address, options); ENVOY_LOG(debug, "Connecting to configured HTTP/1.1 proxy at {}", - transport_socket_options->http11ProxyInfo()->proxy_address->asString()); + proxy_address.value()->asString()); connection = dispatcher.createClientConnection( - transport_socket_options->http11ProxyInfo()->proxy_address, upstream_local_address.address_, + proxy_address.value(), upstream_local_address.address_, socket_factory.createTransportSocket(transport_socket_options, host), upstream_local_address.socket_options_, transport_socket_options); } else if (address_list_or_null != nullptr && address_list_or_null->size() > 1) { @@ -981,13 +1047,14 @@ createOptions(const envoy::config::cluster::v3::Cluster& config, config.protocol_selection() == envoy::config::cluster::v3::Cluster::USE_DOWNSTREAM_PROTOCOL, config.has_http2_protocol_options(), validation_visitor); - RETURN_IF_STATUS_NOT_OK(options_or_error); + RETURN_IF_NOT_OK_REF(options_or_error.status()); return options_or_error.value(); } absl::StatusOr LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProtoWithoutSubset( - const ClusterProto& cluster, ProtobufMessage::ValidationVisitor& visitor) { + LoadBalancerFactoryContext& lb_factory_context, const ClusterProto& cluster, + ProtobufMessage::ValidationVisitor& visitor) { LoadBalancerConfigPtr lb_config; TypedLoadBalancerFactory* lb_factory = nullptr; @@ -1030,12 +1097,13 @@ LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProtoWithoutSubset( ClusterProto::LbPolicy_Name(cluster.lb_policy()))); } - return Result{lb_factory, lb_factory->loadConfig(cluster, visitor)}; + return Result{lb_factory, lb_factory->loadConfig(lb_factory_context, cluster, visitor)}; } absl::StatusOr LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProto( - const ClusterProto& cluster, ProtobufMessage::ValidationVisitor& visitor) { + LoadBalancerFactoryContext& lb_factory_context, const ClusterProto& cluster, + ProtobufMessage::ValidationVisitor& visitor) { // Handle the lb subset config case first. // Note it is possible to have a lb_subset_config without actually having any subset selectors. // In this case the subset load balancer should not be used. @@ -1043,12 +1111,12 @@ LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProto( auto* lb_factory = Config::Utility::getFactoryByName( "envoy.load_balancing_policies.subset"); if (lb_factory != nullptr) { - return Result{lb_factory, lb_factory->loadConfig(cluster, visitor)}; + return Result{lb_factory, lb_factory->loadConfig(lb_factory_context, cluster, visitor)}; } return absl::InvalidArgumentError("No subset load balancer factory found"); } - return getTypedLbConfigFromLegacyProtoWithoutSubset(cluster, visitor); + return getTypedLbConfigFromLegacyProtoWithoutSubset(lb_factory_context, cluster, visitor); } using ProtocolOptionsHashMap = @@ -1140,6 +1208,11 @@ ClusterInfoImpl::ClusterInfoImpl( envoy::config::cluster::v3::UpstreamConnectionOptions::HappyEyeballsConfig>( config.upstream_connection_options().happy_eyeballs_config()) : nullptr), + lrs_report_metric_names_(!config.lrs_report_endpoint_metrics().empty() + ? std::make_unique( + config.lrs_report_endpoint_metrics().begin(), + config.lrs_report_endpoint_metrics().end()) + : nullptr), per_connection_buffer_limit_bytes_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, per_connection_buffer_limit_bytes, 1024 * 1024)), max_response_headers_count_(PROTOBUF_GET_WRAPPED_OR_DEFAULT( @@ -1188,9 +1261,10 @@ ClusterInfoImpl::ClusterInfoImpl( } else { // If load_balancing_policy is not set, we will try to convert legacy lb_policy // to load_balancing_policy and use it. + LoadBalancerFactoryContextImpl lb_factory_context(server_context); auto lb_pair = LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProto( - config, server_context.messageValidationVisitor()); + lb_factory_context, config, server_context.messageValidationVisitor()); if (!lb_pair.ok()) { throwEnvoyExceptionOrPanic(std::string(lb_pair.status().message())); @@ -1221,8 +1295,8 @@ ClusterInfoImpl::ClusterInfoImpl( optional_timeouts_.set(*idle_timeout); } - // Use default (10m) or configured `tcp_pool_idle_timeout`, unless it's set to 0, indicating that - // no timeout should be used. + // Use default (10m) or configured `tcp_pool_idle_timeout`, unless it's set to 0, indicating + // that no timeout should be used. absl::optional tcp_pool_idle_timeout(std::chrono::minutes(10)); if (tcp_protocol_options_ && tcp_protocol_options_->idleTimeout().has_value()) { tcp_pool_idle_timeout = tcp_protocol_options_->idleTimeout(); @@ -1357,13 +1431,14 @@ ClusterInfoImpl::configureLbPolicies(const envoy::config::cluster::v3::Cluster& policy.typed_extension_config(), /*is_optional=*/true); if (factory != nullptr) { // Load and validate the configuration. + LoadBalancerFactoryContextImpl lb_factory_context(context); auto proto_message = factory->createEmptyConfigProto(); Config::Utility::translateOpaqueConfig(policy.typed_extension_config().typed_config(), context.messageValidationVisitor(), *proto_message); load_balancer_factory_ = factory; - load_balancer_config_ = - factory->loadConfig(*proto_message, context.messageValidationVisitor()); + load_balancer_config_ = factory->loadConfig(lb_factory_context, *proto_message, + context.messageValidationVisitor()); break; } diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index 5896e11747c6..e7573e4f50fd 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -55,6 +55,7 @@ #include "source/common/http/http3/codec_stats.h" #include "source/common/init/manager_impl.h" #include "source/common/network/utility.h" +#include "source/common/orca/orca_load_metrics.h" #include "source/common/shared_pool/shared_pool.h" #include "source/common/stats/isolated_store_impl.h" #include "source/common/upstream/edf_scheduler.h" @@ -89,11 +90,13 @@ class LegacyLbPolicyConfigHelper { }; static absl::StatusOr - getTypedLbConfigFromLegacyProtoWithoutSubset(const ClusterProto& cluster, + getTypedLbConfigFromLegacyProtoWithoutSubset(LoadBalancerFactoryContext& lb_factory_context, + const ClusterProto& cluster, ProtobufMessage::ValidationVisitor& visitor); static absl::StatusOr - getTypedLbConfigFromLegacyProto(const ClusterProto& cluster, + getTypedLbConfigFromLegacyProto(LoadBalancerFactoryContext& lb_factory_context, + const ClusterProto& cluster, ProtobufMessage::ValidationVisitor& visitor); }; @@ -223,6 +226,7 @@ class HostDescriptionImplBase : virtual public HostDescription, const std::string& hostnameForHealthChecks() const override { return health_checks_hostname_; } const std::string& hostname() const override { return hostname_; } const envoy::config::core::v3::Locality& locality() const override { return locality_; } + const MetadataConstSharedPtr localityMetadata() const override { return locality_metadata_; } Stats::StatName localityZoneStatName() const override { return locality_zone_stat_name_.statName(); } @@ -428,6 +432,9 @@ class HostImplBase : public Host, const Network::ConnectionSocket::OptionsSharedPtr& options, Network::TransportSocketOptionsConstSharedPtr transport_socket_options, HostDescriptionConstSharedPtr host); + static absl::optional maybeGetProxyRedirectAddress( + const Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + HostDescriptionConstSharedPtr host); private: // Helper function to check multiple health flags at once. @@ -720,7 +727,6 @@ class PrioritySetImpl : public PrioritySet { overprovisioning_factor); } -protected: virtual void runUpdateCallbacks(const HostVector& hosts_added, const HostVector& hosts_removed) { THROW_IF_NOT_OK(member_update_cb_helper_.runCallbacks(hosts_added, hosts_removed)); } @@ -1018,6 +1024,13 @@ class ClusterInfoImpl : public ClusterInfo, return *happy_eyeballs_config_; } + OptRef lrsReportMetricNames() const override { + if (lrs_report_metric_names_ == nullptr) { + return absl::nullopt; + } + return *lrs_report_metric_names_; + } + protected: // Gets the retry budget percent/concurrency from the circuit breaker thresholds. If the retry // budget message is specified, defaults will be filled in if either params are unspecified. @@ -1106,6 +1119,7 @@ class ClusterInfoImpl : public ClusterInfo, UpstreamFactoryContextImpl upstream_context_; std::unique_ptr happy_eyeballs_config_; + const std::unique_ptr lrs_report_metric_names_; // Keep small values like bools and enums at the end of the class to reduce // overhead via alignment diff --git a/source/extensions/clusters/common/logical_host.h b/source/extensions/clusters/common/logical_host.h index 3fe2164d18b5..3c13c909904c 100644 --- a/source/extensions/clusters/common/logical_host.h +++ b/source/extensions/clusters/common/logical_host.h @@ -77,6 +77,9 @@ class RealHostDescription : public HostDescription { // Upstream:HostDescription observers are delegated to logical_host_. bool canary() const override { return logical_host_->canary(); } MetadataConstSharedPtr metadata() const override { return logical_host_->metadata(); } + const MetadataConstSharedPtr localityMetadata() const override { + return logical_host_->localityMetadata(); + } Network::UpstreamTransportSocketFactory& transportSocketFactory() const override { return logical_host_->transportSocketFactory(); diff --git a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc index d80ca3e83eac..4ec0a8298ac9 100644 --- a/source/extensions/clusters/dynamic_forward_proxy/cluster.cc +++ b/source/extensions/clusters/dynamic_forward_proxy/cluster.cc @@ -499,7 +499,7 @@ ClusterFactory::createClusterWithConfig( Extensions::Common::DynamicForwardProxy::DnsCacheManagerSharedPtr cache_manager = cache_manager_factory.get(); auto dns_cache_or_error = cache_manager->getCache(proto_config.dns_cache_config()); - RETURN_IF_STATUS_NOT_OK(dns_cache_or_error); + RETURN_IF_NOT_OK_REF(dns_cache_or_error.status()); absl::Status creation_status = absl::OkStatus(); auto new_cluster = std::shared_ptr( diff --git a/source/extensions/common/aws/metadata_fetcher.cc b/source/extensions/common/aws/metadata_fetcher.cc index f5dbe85eea55..aeaac64661d2 100644 --- a/source/extensions/common/aws/metadata_fetcher.cc +++ b/source/extensions/common/aws/metadata_fetcher.cc @@ -52,6 +52,12 @@ class MetadataFetcherImpl : public MetadataFetcher, ASSERT(!request_); complete_ = false; receiver_ = makeOptRef(receiver); + + // Stop processing if we are shutting down + if (cm_.isShutdown()) { + return; + } + const auto thread_local_cluster = cm_.getThreadLocalCluster(cluster_name_); if (thread_local_cluster == nullptr) { ENVOY_LOG(error, "{} AWS Metadata failed: [cluster = {}] not found", __func__, cluster_name_); diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc index 99b7efcc5b4e..494df335ea64 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc @@ -62,10 +62,7 @@ DnsCacheImpl::DnsCacheImpl( // potential optimization of having the entry be preresolved the first time a true consumer of // this DNS cache asks for it. const std::string host = - (Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.normalize_host_for_preresolve_dfp_dns")) - ? DnsHostInfo::normalizeHostForDfp(hostname.address(), hostname.port_value()) - : hostname.address(); + DnsHostInfo::normalizeHostForDfp(hostname.address(), hostname.port_value()); ENVOY_LOG(debug, "DNS pre-resolve starting for host {}", host); startCacheLoad(host, hostname.port_value(), false, false); } diff --git a/source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.cc b/source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.cc index e15cfe325af1..cb98cfae2b09 100644 --- a/source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.cc +++ b/source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.cc @@ -27,7 +27,7 @@ absl::StatusOr DnsCacheManagerImpl::getCache( } auto cache_or_status = DnsCacheImpl::createDnsCacheImpl(context_, config); - RETURN_IF_STATUS_NOT_OK(cache_or_status); + RETURN_IF_NOT_OK_REF(cache_or_status.status()); DnsCacheSharedPtr new_cache = std::move(cache_or_status.value()); caches_.emplace(config.name(), ActiveCache{config, new_cache}); return new_cache; diff --git a/source/extensions/config_subscription/grpc/grpc_mux_failover.h b/source/extensions/config_subscription/grpc/grpc_mux_failover.h index 00876af5c555..745e1be9409f 100644 --- a/source/extensions/config_subscription/grpc/grpc_mux_failover.h +++ b/source/extensions/config_subscription/grpc/grpc_mux_failover.h @@ -30,19 +30,25 @@ namespace Config { * will be followed by the GrpcMuxFailover calling the GrpcStreamCallbacks on the GrpcMux * object that initialized it. * - * Note: this class is WIP and should be considered alpha! - * At the moment, the supported policy is as follows: + * To simplify the state-machine, Envoy can be in one of the mutually exclusive states: + * ConnectingToPrimary - attempting to connect to the primary source. + * ConnectedToPrimary - after receiving a response from the primary source. + * ConnectingToFailover - attempting to connect to the failover source. + * ConnectedToFailover - after receiving a response from the failover source. + * None - not attempting to connect or connected to any source (e.g., upon initialization). + * * The GrpcMuxFailover attempts to establish a connection to the primary source. Once a response is * received from the primary source it will be considered available, and the failover will not be * used. Any future reconnection attempts will be to the primary source only. * However, if no response is received from the primary source, and accessing the primary has * failed 2 times in a row, the GrpcMuxFailover will attempt to establish a connection to the - * failover source. If a response from the failover source is received, only the failover source - * will be used. - * If the failover source is unavailable, the GrpcMuxFailover will alternate between attempts - * to reconnect to the primary source and the failover source. - * In the future, this behavior may change, and the GrpcMuxFailover will always - * prefer the primary source, even if prior connection to the failover was successful. + * failover source. Envoy will keep alternating between the primary and failover sources attempting + * to connect to one of them. If a response from the failover source is received, it will be the + * source of configuration until the connection is closed. In case the failover connection is + * closed, Envoy will attempt to connect to the primary, before retrying to connect to the failover + * source. If the failover source is unavailable or a connection to it is closed, the + * GrpcMuxFailover will alternate between attempts to reconnect to the primary source and the + * failover source. * TODO(adisuissa): The number of consecutive failures is currently statically * defined, and may be converted to a config field in the future. */ @@ -64,8 +70,7 @@ class GrpcMuxFailover : public GrpcStreamInterface, Event::Dispatcher& dispatcher) : grpc_mux_callbacks_(grpc_mux_callbacks), primary_callbacks_(*this), primary_grpc_stream_(std::move(primary_stream_creator(&primary_callbacks_))), - connecting_to_primary_(false), connecting_to_failover_(false), - connected_to_(ConnectedState::None), ever_connected_to_(ConnectedState::None) { + connection_state_(ConnectionState::None), ever_connected_to_primary_(false) { ASSERT(primary_grpc_stream_ != nullptr); if (failover_stream_creator.has_value()) { ENVOY_LOG(warn, "Using xDS-Failover. Note that the implementation is currently considered " @@ -84,32 +89,34 @@ class GrpcMuxFailover : public GrpcStreamInterface, // Attempts to establish a new stream to the either the primary or failover source. void establishNewStream() override { // Attempt establishing a connection to the primary source. - // This method may be called multiple times, even if the primary stream is already - // established or in the process of being established. + // This method may be called multiple times, even if the primary/failover stream + // is already established or in the process of being established. if (complete_retry_timer_) { complete_retry_timer_->disableTimer(); } - // First check if Envoy ever connected to the primary/failover, and if so - // persist attempts to that source. - if (ever_connected_to_ == ConnectedState::Primary) { - ASSERT(!connecting_to_failover_); - ENVOY_LOG_MISC(trace, "Attempting to reconnect to the primary gRPC source, as a connection " - "to it was previously established."); - establishStreamToPrimaryIfNotConnected(); - return; - } else if (ever_connected_to_ == ConnectedState::Failover) { - ASSERT(!connecting_to_primary_); - ENVOY_LOG_MISC(trace, "Attempting to reconnect to the failover gRPC source, as a connection " - "to it was previously established."); - establishStreamToFailoverIfNotConnected(); + // If already connected to one of the source, return. + if (connection_state_ == ConnectionState::ConnectedToPrimary || + connection_state_ == ConnectionState::ConnectedToFailover) { + ENVOY_LOG_MISC(trace, + "Already connected to an xDS server, skipping establishNewStream() call"); return; } - // No prior connection was established, prefer the primary over the failover. - if (connecting_to_failover_) { - establishStreamToFailoverIfNotConnected(); + // connection_state_ is either None, ConnectingToPrimary or + // ConnectingToFailover. In the first 2 cases try to connect to the primary + // (preferring the primary in the case of None), and in the third case + // try to connect to the failover. + // Note that if a connection to the primary source was ever successful, the + // failover manager will keep setting connection_state_ to either None or + // ConnectingToPrimary, which ensures that only the primary stream will be + // established. + if (connection_state_ == ConnectionState::ConnectingToFailover) { + ASSERT(!ever_connected_to_primary_); + failover_grpc_stream_->establishNewStream(); } else { - // Either connecting to primary or connected to it, or neither. - establishStreamToPrimaryIfNotConnected(); + ASSERT(connection_state_ == ConnectionState::None || + connection_state_ == ConnectionState::ConnectingToPrimary); + connection_state_ = ConnectionState::ConnectingToPrimary; + primary_grpc_stream_->establishNewStream(); } } @@ -125,6 +132,7 @@ class GrpcMuxFailover : public GrpcStreamInterface, // Sends a message using the underlying stream. void sendMessage(const RequestType& request) override { if (connectingToOrConnectedToFailover()) { + ASSERT(!ever_connected_to_primary_); failover_grpc_stream_->sendMessage(request); return; } @@ -172,10 +180,9 @@ class GrpcMuxFailover : public GrpcStreamInterface, // Retries to connect again to the primary and then (possibly) to the // failover. Assumes that no connection has been made or is being attempted. void retryConnections() { - ASSERT(!connecting_to_primary_ && !connecting_to_failover_ && - (connected_to_ == ConnectedState::None)); + ASSERT(connection_state_ == ConnectionState::None); ENVOY_LOG(trace, "Expired timer, retrying to reconnect to the primary xDS server."); - connecting_to_primary_ = true; + connection_state_ = ConnectionState::ConnectingToPrimary; primary_grpc_stream_->establishNewStream(); } @@ -191,21 +198,19 @@ class GrpcMuxFailover : public GrpcStreamInterface, // considering the primary source as available. // Calling the onStreamEstablished() callback on the GrpcMux object will // trigger the GrpcMux to start sending requests. - ASSERT(parent_.connecting_to_primary_ && !parent_.connecting_to_failover_ && - (parent_.connected_to_ == ConnectedState::None)); + ASSERT(parent_.connection_state_ == ConnectionState::ConnectingToPrimary); parent_.grpc_mux_callbacks_.onStreamEstablished(); } void onEstablishmentFailure() override { // This will be called when the primary stream fails to establish a connection, or after the // connection was closed. - ASSERT(parent_.connectingToOrConnectedToPrimary() && - !parent_.connectingToOrConnectedToFailover()); + ASSERT(parent_.connectingToOrConnectedToPrimary()); // If there's no failover supported, this will just be a pass-through // callback. if (parent_.failover_grpc_stream_ != nullptr) { - if (parent_.connecting_to_primary_ && - (parent_.ever_connected_to_ != ConnectedState::Primary)) { + if (parent_.connection_state_ == ConnectionState::ConnectingToPrimary && + !parent_.ever_connected_to_primary_) { // If there are 2 consecutive failures to the primary, Envoy will try to connect to the // failover. primary_consecutive_failures_++; @@ -214,12 +219,14 @@ class GrpcMuxFailover : public GrpcStreamInterface, // Terminate the primary stream and establish a connection to the failover stream. ENVOY_LOG(debug, "Primary xDS stream failed to establish a connection at least 2 times " "in a row. Attempting to connect to the failover stream."); - parent_.connecting_to_primary_ = false; // This will close the stream and prevent the retry timer from // reconnecting to the primary source. + // TODO(adisuissa): need to ensure that when moving between primary and failover, + // the initial_resource_versions that are sent are empty. This will be + // done in a followup PR. parent_.primary_grpc_stream_->closeStream(); parent_.grpc_mux_callbacks_.onEstablishmentFailure(); - parent_.connecting_to_failover_ = true; + parent_.connection_state_ = ConnectionState::ConnectingToFailover; parent_.failover_grpc_stream_->establishNewStream(); return; } @@ -229,8 +236,7 @@ class GrpcMuxFailover : public GrpcStreamInterface, // later by the underlying grpc stream. ENVOY_LOG_MISC(trace, "Not trying to connect to failover. Will try again to reconnect to the " "primary (upon retry)."); - parent_.connecting_to_primary_ = true; - parent_.connected_to_ = ConnectedState::None; + parent_.connection_state_ = ConnectionState::ConnectingToPrimary; parent_.grpc_mux_callbacks_.onEstablishmentFailure(); } @@ -240,10 +246,9 @@ class GrpcMuxFailover : public GrpcStreamInterface, !parent_.connectingToOrConnectedToFailover()); // Received a response from the primary. The primary is now considered available (no failover // will be attempted). - parent_.ever_connected_to_ = ConnectedState::Primary; + parent_.ever_connected_to_primary_ = true; primary_consecutive_failures_ = 0; - parent_.connected_to_ = ConnectedState::Primary; - parent_.connecting_to_primary_ = false; + parent_.connection_state_ = ConnectionState::ConnectedToPrimary; parent_.grpc_mux_callbacks_.onDiscoveryResponse(std::move(message), control_plane_stats); } @@ -268,55 +273,45 @@ class GrpcMuxFailover : public GrpcStreamInterface, // the first response to be received before considering the failover available. // Calling the onStreamEstablished() callback on the GrpcMux object will // trigger the GrpcMux to start sending requests. - ASSERT(parent_.connecting_to_failover_ && !parent_.connecting_to_primary_ && - (parent_.connected_to_ == ConnectedState::None)); + ASSERT(parent_.connection_state_ == ConnectionState::ConnectingToFailover); + ASSERT(!parent_.ever_connected_to_primary_); parent_.grpc_mux_callbacks_.onStreamEstablished(); } void onEstablishmentFailure() override { // This will be called when the failover stream fails to establish a connection, or after the // connection was closed. - ASSERT(parent_.connectingToOrConnectedToFailover() && - !parent_.connectingToOrConnectedToPrimary()); - if (parent_.ever_connected_to_ != ConnectedState::Failover) { - ASSERT(parent_.connecting_to_failover_); - // If Envoy never established a connecting the failover, it will try to connect to the - // primary next. - ENVOY_LOG(debug, "Failover xDS stream failed to establish a connection. Attempting to " - "connect to the primary stream."); - parent_.connecting_to_failover_ = false; - // This will close the stream and prevent the retry timer from - // reconnecting to the failover source. - parent_.failover_grpc_stream_->closeStream(); - parent_.grpc_mux_callbacks_.onEstablishmentFailure(); - // Wait for a short period of time before retrying to reconnect to the - // primary, reducing strain on the network/servers in case of an issue. - // TODO(adisuissa): In the future, the reconnection attempts to the - // primary and failover sources will be decoupled, as each will use its - // own backoff timer, and this will not be needed. - parent_.complete_retry_timer_->enableTimer(std::chrono::milliseconds(500)); - return; - } - // Pass along the failure to the GrpcMux object. Retry will be triggered - // later by the underlying grpc stream. - ENVOY_LOG_MISC(trace, "Not trying to connect to primary. Will try again to reconnect to the " - "failover (upon retry)."); - parent_.connecting_to_failover_ = true; - parent_.connected_to_ = ConnectedState::None; + ASSERT(parent_.connectingToOrConnectedToFailover()); + // Either this was an intentional disconnection from the failover source, + // or unintentional. Either way, try to connect to the primary next. + ENVOY_LOG(debug, "Failover xDS stream diconnected (either after establishing a connection or " + "before). Attempting to connect to the primary stream."); + + // This will close the stream and prevent the retry timer from + // reconnecting to the failover source. + // TODO(adisuissa): need to ensure that when moving between primary and failover, + // the initial_resource_versions that are sent are empty. This will be + // done in a followup PR. + parent_.failover_grpc_stream_->closeStream(); parent_.grpc_mux_callbacks_.onEstablishmentFailure(); + // Setting the connection state to None, and when the retry timer will + // expire, Envoy will try to connect to the primary source. + parent_.connection_state_ = ConnectionState::None; + // Wait for a short period of time before retrying to reconnect to the + // primary, reducing strain on the network/servers in case of an issue. + // TODO(adisuissa): need to use the primary source's retry timer here, to wait + // for the next time to connect to the primary. This requires a refactor + // of the retry timer and moving it from the grpc_stream to here. + parent_.complete_retry_timer_->enableTimer(std::chrono::milliseconds(500)); } void onDiscoveryResponse(ResponseProtoPtr&& message, ControlPlaneStats& control_plane_stats) override { - ASSERT(parent_.connectingToOrConnectedToFailover() && - !parent_.connectingToOrConnectedToPrimary()); + ASSERT(parent_.connectingToOrConnectedToFailover()); + ASSERT(!parent_.ever_connected_to_primary_); // Received a response from the failover. The failover is now considered available (no going // back to the primary will be attempted). - // TODO(adisuissa): This will be modified in the future, when allowing the primary to always - // be preferred over the failover. - parent_.ever_connected_to_ = ConnectedState::Failover; - parent_.connected_to_ = ConnectedState::Failover; - parent_.connecting_to_failover_ = false; + parent_.connection_state_ = ConnectionState::ConnectedToFailover; parent_.grpc_mux_callbacks_.onDiscoveryResponse(std::move(message), control_plane_stats); } @@ -332,30 +327,14 @@ class GrpcMuxFailover : public GrpcStreamInterface, // Returns true iff the state is connecting to primary or connected to it. bool connectingToOrConnectedToPrimary() const { - return connecting_to_primary_ || (connected_to_ == ConnectedState::Primary); + return connection_state_ == ConnectionState::ConnectingToPrimary || + connection_state_ == ConnectionState::ConnectedToPrimary; } // Returns true iff the state is connecting to failover or connected to it. bool connectingToOrConnectedToFailover() const { - return connecting_to_failover_ || (connected_to_ == ConnectedState::Failover); - } - - // Establishes a new stream to the primary source if not connected to it. - void establishStreamToPrimaryIfNotConnected() { - if (connected_to_ != ConnectedState::Primary) { - ASSERT(connected_to_ == ConnectedState::None); - connecting_to_primary_ = true; - primary_grpc_stream_->establishNewStream(); - } - } - - // Establishes a new stream to the failover source if not connected to it. - void establishStreamToFailoverIfNotConnected() { - if (connected_to_ != ConnectedState::Failover) { - ASSERT(connected_to_ == ConnectedState::None); - connecting_to_failover_ = true; - failover_grpc_stream_->establishNewStream(); - } + return connection_state_ == ConnectionState::ConnectingToFailover || + connection_state_ == ConnectionState::ConnectedToFailover; } // The following method overrides are to allow GrpcMuxFailover to extend the @@ -389,31 +368,33 @@ class GrpcMuxFailover : public GrpcStreamInterface, // initialized when failover is supported. Event::TimerPtr complete_retry_timer_{nullptr}; - enum class ConnectedState { None, Primary, Failover }; + enum class ConnectionState { + None, + ConnectingToPrimary, + ConnectedToPrimary, + ConnectingToFailover, + ConnectedToFailover + }; // Flags to keep track of the state of connections to primary/failover. - // All initialized to false/None, as there is no connection process during - // initialization. - // The object starts with all the connecting flags set to false, and - // connected_to to None. Once a new stream is attempted, - // connecting_to_primary_ will become true, until a response will be received - // from the primary (connected_to_ will become Primary), or a failure - // to establish a connection to the primary occurs. In the latter case, if - // Envoy attempts to reconnect to the primary, connecting_to_primary_ will - // stay true, but if it attempts to connect to the failover, connecting_to_primary_ - // will be set to false, and connecting_to_failover_ will be true. - // The values of connecting_to_failover_ and connected_to_ set to Failover will be - // determined similar to the primary variants. + // The object starts with all the connecting_to and connected_to flags set + // to None. + // Once a new stream is attempted, connecting_to_ will become Primary, until + // a response will be received from the primary (connected_to_ will be set + // to Primary), or a failure to establish a connection to the primary occurs. + // In the latter case, if Envoy attempts to reconnect to the primary, + // connecting_to_ will stay Primary, but if it attempts to connect to the failover, + // connecting_to_ will be set to Failover. + // If Envoy successfully connects to the failover, connected_to_ will be set + // to Failover. // Note that while Envoy can only be connected to a single source (mutually // exclusive), it can attempt connecting to more than one source at a time. - bool connecting_to_primary_{false}; - bool connecting_to_failover_{false}; - ConnectedState connected_to_; + ConnectionState connection_state_; // A flag that keeps track of whether Envoy successfully connected to either the - // primary or failover source. Envoy successfully connected to a source once - // it receives a response from it. - ConnectedState ever_connected_to_; + // primary or failover source. Envoy is considered successfully connected to a source + // once it receives a response from it. + bool ever_connected_to_primary_{false}; }; } // namespace Config diff --git a/source/extensions/dynamic_modules/BUILD b/source/extensions/dynamic_modules/BUILD new file mode 100644 index 000000000000..008e2ad84734 --- /dev/null +++ b/source/extensions/dynamic_modules/BUILD @@ -0,0 +1,22 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "dynamic_modules_lib", + srcs = [ + "dynamic_modules.cc", + ], + hdrs = [ + "dynamic_modules.h", + ], + deps = [ + "//envoy/common:exception_lib", + ], +) diff --git a/source/extensions/dynamic_modules/dynamic_modules.cc b/source/extensions/dynamic_modules/dynamic_modules.cc new file mode 100644 index 000000000000..e28917fac16f --- /dev/null +++ b/source/extensions/dynamic_modules/dynamic_modules.cc @@ -0,0 +1,44 @@ +#include "source/extensions/dynamic_modules/dynamic_modules.h" + +#include + +#include +#include + +#include "envoy/common/exception.h" + +namespace Envoy { +namespace Extensions { +namespace DynamicModules { + +absl::StatusOr newDynamicModule(const absl::string_view object_file_path, + const bool do_not_close) { + // RTLD_LOCAL is always needed to avoid collisions between multiple modules. + // RTLD_LAZY is required for not only performance but also simply to load the module, otherwise + // dlopen results in Invalid argument. + int mode = RTLD_LOCAL | RTLD_LAZY; + if (do_not_close) { + mode |= RTLD_NODELETE; + } + + const std::filesystem::path file_path_absolute = std::filesystem::absolute(object_file_path); + void* handle = dlopen(file_path_absolute.c_str(), mode); + if (handle == nullptr) { + return absl::InvalidArgumentError( + absl::StrCat("Failed to load dynamic module: ", object_file_path, " : ", dlerror())); + } + return std::make_shared(handle); +} + +DynamicModule::~DynamicModule() { dlclose(handle_); } + +void* DynamicModule::getSymbol(const absl::string_view symbol_ref) const { + // TODO(mathetake): maybe we should accept null-terminated const char* instead of string_view to + // avoid unnecessary copy because it is likely that this is only called for a constant string, + // though this is not a performance critical path. + return dlsym(handle_, std::string(symbol_ref).c_str()); +} + +} // namespace DynamicModules +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/dynamic_modules/dynamic_modules.h b/source/extensions/dynamic_modules/dynamic_modules.h new file mode 100644 index 000000000000..5e20f729cb2a --- /dev/null +++ b/source/extensions/dynamic_modules/dynamic_modules.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" + +namespace Envoy { +namespace Extensions { +namespace DynamicModules { + +/** + * A class for loading and managing dynamic modules. This corresponds to a single dlopen handle. + * When the DynamicModule object is destroyed, the dlopen handle is closed. + * + * This class is supposed to be initialized once in the main thread and can be shared with other + * threads. + */ +class DynamicModule { +public: + DynamicModule(void* handle) : handle_(handle) {} + ~DynamicModule(); + + /** + * Get a function pointer from the dynamic module with a specific type. + * @param T the function pointer type to cast the symbol to. + * @param symbol_ref the symbol to look up. + * @return the symbol if found, otherwise nullptr. + */ + template T getFunctionPointer(const absl::string_view symbol_ref) const { + static_assert(std::is_pointer::value && + std::is_function::type>::value, + "T must be a function pointer type"); + return reinterpret_cast(getSymbol(symbol_ref)); + } + +private: + /** + * Get a symbol from the dynamic module. + * @param symbol_ref the symbol to look up. + * @return the symbol if found, otherwise nullptr. + */ + void* getSymbol(const absl::string_view symbol_ref) const; + + // The raw dlopen handle that can be used to look up symbols. + void* handle_; +}; + +using DynamicModuleSharedPtr = std::shared_ptr; + +/** + * Creates a new DynamicModule. + * @param object_file_path the path to the object file to load. + * @param do_not_close if true, the dlopen will be called with RTLD_NODELETE, so the loaded object + * will not be destroyed. This is useful when an object has some global state that should not be + * terminated. For example, c-shared objects compiled by Go doesn't support dlclose + * https://github.com/golang/go/issues/11100. + */ +absl::StatusOr newDynamicModule(const absl::string_view object_file_path, + const bool do_not_close); + +} // namespace DynamicModules +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index ed7cb6a0391d..ee10c1279eac 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -81,6 +81,7 @@ EXTENSIONS = { "envoy.matching.matchers.ip": "//source/extensions/matching/input_matchers/ip:config", "envoy.matching.matchers.runtime_fraction": "//source/extensions/matching/input_matchers/runtime_fraction:config", "envoy.matching.matchers.cel_matcher": "//source/extensions/matching/input_matchers/cel_matcher:config", + "envoy.matching.matchers.metadata_matcher": "//source/extensions/matching/input_matchers/metadata:config", # # Network Matchers @@ -109,6 +110,11 @@ EXTENSIONS = { # "envoy.matching.inputs.cel_data_input": "//source/extensions/matching/http/cel_input:cel_input_lib", + # + # Dynamic Metadata Matching Input + # + "envoy.matching.inputs.dynamic_metadata": "//source/extensions/matching/http/metadata_input:metadata_input_lib", + # # Matching actions # @@ -530,8 +536,8 @@ EXTENSIONS = { # These can be changed to ["//visibility:public"], for downstream builds which # need to directly reference Envoy extensions. -EXTENSION_CONFIG_VISIBILITY = ["//:extension_config", "//:contrib_library", "//:examples_library", "//:mobile_library"] -EXTENSION_PACKAGE_VISIBILITY = ["//:extension_library", "//:contrib_library", "//:examples_library", "//:mobile_library"] +EXTENSION_CONFIG_VISIBILITY = ["//:extension_config", "//:contrib_library", "//:mobile_library"] +EXTENSION_PACKAGE_VISIBILITY = ["//:extension_library", "//:contrib_library", "//:mobile_library"] CONTRIB_EXTENSION_PACKAGE_VISIBILITY = ["//:contrib_library"] MOBILE_PACKAGE_VISIBILITY = ["//:mobile_library"] diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index 483b4294bc84..35893425a135 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -1565,6 +1565,13 @@ envoy.matching.inputs.filter_state: status: stable type_urls: - envoy.extensions.matching.common_inputs.network.v3.FilterStateInput +envoy.matching.inputs.dynamic_metadata: + categories: + - envoy.matching.http.input + security_posture: unknown + status: stable + type_urls: + - envoy.extensions.matching.common_inputs.network.v3.DynamicMetadataInput envoy.matching.inputs.uri_san: categories: - envoy.matching.http.input @@ -1597,6 +1604,13 @@ envoy.matching.custom_matchers.trie_matcher: status: stable type_urls: - xds.type.matcher.v3.IPMatcher +envoy.matching.matchers.metadata_matcher: + categories: + - envoy.matching.input_matchers + security_posture: unknown + status: alpha + type_urls: + - envoy.extensions.matching.input_matchers.metadata.v3.Metadata envoy.load_balancing_policies.least_request: categories: - envoy.load_balancing_policies diff --git a/source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.cc b/source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.cc index 22b72b803224..dab5d014d109 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.cc +++ b/source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.cc @@ -114,11 +114,7 @@ void GrpcClientImpl::onSuccess(std::unique_ptrok_response(); copyOkResponseMutations(authz_response, ok_response); } - } else if (response->status().code() == Grpc::Status::WellKnownGrpcStatus::PermissionDenied || - response->status().code() == Grpc::Status::WellKnownGrpcStatus::Unauthenticated || - !Runtime::runtimeFeatureEnabled( - "envoy.reloadable_features.process_ext_authz_grpc_error_codes_as_errors")) { - // The request was explicitly forbidden by the external authz server. + } else { span.setTag(TracingConstants::get().TraceStatus, TracingConstants::get().TraceUnauthz); authz_response->status = CheckStatus::Denied; @@ -133,12 +129,6 @@ void GrpcClientImpl::onSuccess(std::unique_ptrbody = response->denied_response().body(); } - } else { - // Unexpected response from external authz server is interpreted as failure - ENVOY_LOG(trace, "CheckRequest call failed with status: {}", - Grpc::Utility::grpcStatusToString(response->status().code())); - authz_response->status = CheckStatus::Error; - authz_response->status_code = Http::Code::Forbidden; } // OkHttpResponse.dynamic_metadata is deprecated. Until OkHttpResponse.dynamic_metadata is diff --git a/source/extensions/filters/http/cache/cache_filter.cc b/source/extensions/filters/http/cache/cache_filter.cc index 658b1446d7b8..03f5557a8538 100644 --- a/source/extensions/filters/http/cache/cache_filter.cc +++ b/source/extensions/filters/http/cache/cache_filter.cc @@ -485,8 +485,16 @@ void CacheFilter::onTrailers(Http::ResponseTrailerMapPtr&& trailers) { } if (filter_state_ == FilterState::DecodeServingFromCache) { decoder_callbacks_->encodeTrailers(std::move(trailers)); + // Filter can potentially be destroyed during encodeTrailers. + if (filter_state_ == FilterState::Destroyed) { + return; + } } else { Http::ResponseTrailerMap& response_trailers = encoder_callbacks_->addEncodedTrailers(); + // Filter can potentially be destroyed during addEncodedTrailers. + if (filter_state_ == FilterState::Destroyed) { + return; + } response_trailers = std::move(*trailers); } finalizeEncodingCachedResponse(); @@ -677,6 +685,10 @@ void CacheFilter::encodeCachedResponse() { if (filter_state_ == FilterState::DecodeServingFromCache) { decoder_callbacks_->encodeHeaders(std::move(lookup_result_->headers_), end_stream, CacheResponseCodeDetails::get().ResponseFromCacheFilter); + // Filter can potentially be destroyed during encodeHeaders. + if (filter_state_ == FilterState::Destroyed) { + return; + } } if (filter_state_ == FilterState::EncodeServingFromCache && is_head_request_) { filter_state_ = FilterState::ResponseServedFromCache; @@ -698,6 +710,10 @@ void CacheFilter::finalizeEncodingCachedResponse() { // encodeHeaders returned StopIteration waiting for finishing encoding the cached response -- // continue encoding. encoder_callbacks_->continueEncoding(); + // Filter can potentially be destroyed during continueEncoding. + if (filter_state_ == FilterState::Destroyed) { + return; + } } filter_state_ = FilterState::ResponseServedFromCache; } diff --git a/source/extensions/filters/http/common/pass_through_filter.h b/source/extensions/filters/http/common/pass_through_filter.h index ad299e47da15..e6291b9e3dd1 100644 --- a/source/extensions/filters/http/common/pass_through_filter.h +++ b/source/extensions/filters/http/common/pass_through_filter.h @@ -62,6 +62,10 @@ class PassThroughEncoderFilter : public virtual StreamEncoderFilter { // A filter which passes all data through with Continue status. class PassThroughFilter : public StreamFilter, public PassThroughDecoderFilter, - public PassThroughEncoderFilter {}; + public PassThroughEncoderFilter { +public: + // Http::StreamFilterBase + void onDestroy() override {} +}; } // namespace Http } // namespace Envoy diff --git a/source/extensions/filters/http/composite/action.h b/source/extensions/filters/http/composite/action.h index dd06a0a924b9..834b757a573f 100644 --- a/source/extensions/filters/http/composite/action.h +++ b/source/extensions/filters/http/composite/action.h @@ -11,8 +11,8 @@ namespace Extensions { namespace HttpFilters { namespace Composite { -using HttpExtensionConfigProviderSharedPtr = std::shared_ptr< - Config::DynamicExtensionConfigProvider>; +using HttpExtensionConfigProviderSharedPtr = + std::shared_ptr>; class ExecuteFilterAction : public Matcher::ActionBase< @@ -80,14 +80,11 @@ class ExecuteFilterActionFactory return nullptr; } - auto config_value = provider->config(); - if (config_value.has_value()) { - auto factory_cb = config_value.value().get().factory_cb; - return std::make_unique(factory_cb, n); + if (auto config_value = provider->config(); config_value.has_value()) { + return std::make_unique(config_value.ref(), n); } // There is no dynamic config available. Apply missing config filter. - auto factory_cb = Envoy::Http::MissingConfigFilterFactory; - return std::make_unique(factory_cb, n); + return std::make_unique(Envoy::Http::MissingConfigFilterFactory, n); }; } diff --git a/source/extensions/filters/http/ext_authz/config.cc b/source/extensions/filters/http/ext_authz/config.cc index 87a20cbd12e9..069029b2eb5d 100644 --- a/source/extensions/filters/http/ext_authz/config.cc +++ b/source/extensions/filters/http/ext_authz/config.cc @@ -20,17 +20,14 @@ namespace Extensions { namespace HttpFilters { namespace ExtAuthz { -Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( +Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoWithServerContextTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config, - const std::string& stats_prefix, Server::Configuration::FactoryContext& context) { - auto& server_context = context.serverFactoryContext(); - - const auto filter_config = - std::make_shared(proto_config, context.scope(), stats_prefix, server_context); + const std::string& stats_prefix, Server::Configuration::ServerFactoryContext& server_context) { + const auto filter_config = std::make_shared(proto_config, server_context.scope(), + stats_prefix, server_context); // The callback is created in main thread and executed in worker thread, variables except factory // context must be captured by value into the callback. Http::FilterFactoryCb callback; - if (proto_config.has_http_service()) { // Raw HTTP client. const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config.http_service().server_uri(), @@ -48,24 +45,21 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped( // gRPC client. const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config.grpc_service(), timeout, DefaultTimeout); - THROW_IF_NOT_OK(Config::Utility::checkTransportVersion(proto_config)); Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key = Envoy::Grpc::GrpcServiceConfigWithHashKey(proto_config.grpc_service()); - callback = [&context, filter_config, timeout_ms, + callback = [&server_context, filter_config, timeout_ms, config_with_hash_key](Http::FilterChainFactoryCallbacks& callbacks) { - auto client_or_error = - context.serverFactoryContext() - .clusterManager() - .grpcAsyncClientManager() - .getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true); + auto client_or_error = server_context.clusterManager() + .grpcAsyncClientManager() + .getOrCreateRawAsyncClientWithHashKey( + config_with_hash_key, server_context.scope(), true); THROW_IF_STATUS_NOT_OK(client_or_error, throw); auto client = std::make_unique( client_or_error.value(), std::chrono::milliseconds(timeout_ms)); callbacks.addStreamFilter(std::make_shared(filter_config, std::move(client))); }; } - return callback; } diff --git a/source/extensions/filters/http/ext_authz/config.h b/source/extensions/filters/http/ext_authz/config.h index a5cddfb6a12c..cd67240833b2 100644 --- a/source/extensions/filters/http/ext_authz/config.h +++ b/source/extensions/filters/http/ext_authz/config.h @@ -25,7 +25,15 @@ class ExtAuthzFilterConfig static constexpr uint64_t DefaultTimeout = 200; Http::FilterFactoryCb createFilterFactoryFromProtoTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config, - const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override; + const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override { + return createFilterFactoryFromProtoWithServerContextTyped(proto_config, stats_prefix, + context.serverFactoryContext()); + } + + Http::FilterFactoryCb createFilterFactoryFromProtoWithServerContextTyped( + const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config, + const std::string& stats_prefix, + Server::Configuration::ServerFactoryContext& server_context) override; Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped( const envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute& proto_config, diff --git a/source/extensions/filters/http/ext_proc/client.h b/source/extensions/filters/http/ext_proc/client.h index 79913d16489b..54493c094fe3 100644 --- a/source/extensions/filters/http/ext_proc/client.h +++ b/source/extensions/filters/http/ext_proc/client.h @@ -24,6 +24,7 @@ class ExternalProcessorStream { // Idempotent close. Return true if it actually closed. virtual bool close() PURE; virtual const StreamInfo::StreamInfo& streamInfo() const PURE; + virtual StreamInfo::StreamInfo& streamInfo() PURE; virtual void notifyFilterDestroy() PURE; }; diff --git a/source/extensions/filters/http/ext_proc/client_impl.h b/source/extensions/filters/http/ext_proc/client_impl.h index d0c08d24f507..745bd3f167c8 100644 --- a/source/extensions/filters/http/ext_proc/client_impl.h +++ b/source/extensions/filters/http/ext_proc/client_impl.h @@ -60,8 +60,12 @@ class ExternalProcessorStreamImpl : public ExternalProcessorStream, // Unregister the watermark callbacks(if any) to prevent access of filter callbacks after // the filter object is destroyed. - if (grpc_side_stream_flow_control_ && !stream_closed_) { - stream_.removeWatermarkCallbacks(); + if (!stream_closed_) { + // Remove the parent stream info to avoid a dangling reference. + stream_.streamInfo().clearParentStreamInfo(); + if (grpc_side_stream_flow_control_) { + stream_.removeWatermarkCallbacks(); + } } } @@ -74,6 +78,7 @@ class ExternalProcessorStreamImpl : public ExternalProcessorStream, void onReceiveTrailingMetadata(Http::ResponseTrailerMapPtr&& metadata) override; void onRemoteClose(Grpc::Status::GrpcStatus status, const std::string& message) override; const StreamInfo::StreamInfo& streamInfo() const override { return stream_.streamInfo(); } + StreamInfo::StreamInfo& streamInfo() override { return stream_.streamInfo(); } bool grpcSidestreamFlowControl() { return grpc_side_stream_flow_control_; } diff --git a/source/extensions/filters/http/ext_proc/ext_proc.cc b/source/extensions/filters/http/ext_proc/ext_proc.cc index 95d551f42cb3..5130208e1b5d 100644 --- a/source/extensions/filters/http/ext_proc/ext_proc.cc +++ b/source/extensions/filters/http/ext_proc/ext_proc.cc @@ -344,7 +344,7 @@ Filter::StreamOpenState Filter::openStream() { auto options = Http::AsyncClient::StreamOptions() .setParentSpan(decoder_callbacks_->activeSpan()) .setParentContext(grpc_context) - .setBufferBodyForRetry(true); + .setBufferBodyForRetry(grpc_service_.has_retry_policy()); ExternalProcessorStreamPtr stream_object = client_->start(*this, config_with_hash_key_, options, watermark_callbacks_); @@ -358,9 +358,7 @@ Filter::StreamOpenState Filter::openStream() { } stats_.streams_started_.inc(); - // TODO(tyxia) Switch to address of stream - stream_ = config_->threadLocalStreamManager().store(decoder_callbacks_->streamId(), - std::move(stream_object), config_->stats(), + stream_ = config_->threadLocalStreamManager().store(std::move(stream_object), config_->stats(), config_->deferredCloseTimeout()); // For custom access logging purposes. Applicable only for Envoy gRPC as Google gRPC does not // have a proper implementation of streamInfo. @@ -377,8 +375,8 @@ void Filter::closeStream() { if (stream_->close()) { stats_.streams_closed_.inc(); } + config_->threadLocalStreamManager().erase(stream_); stream_ = nullptr; - config_->threadLocalStreamManager().erase(decoder_callbacks_->streamId()); } else { ENVOY_LOG(debug, "Stream already closed"); } @@ -386,8 +384,7 @@ void Filter::closeStream() { void Filter::deferredCloseStream() { ENVOY_LOG(debug, "Calling deferred close on stream"); - config_->threadLocalStreamManager().deferredErase(decoder_callbacks_->streamId(), - filter_callbacks_->dispatcher()); + config_->threadLocalStreamManager().deferredErase(stream_, filter_callbacks_->dispatcher()); } void Filter::onDestroy() { @@ -1360,28 +1357,24 @@ void Filter::mergePerRouteConfig() { } } -void DeferredDeletableStream::closeStreamOnTimer(uint64_t stream_id) { +void DeferredDeletableStream::closeStreamOnTimer() { // Close the stream. if (stream_) { ENVOY_LOG(debug, "Closing the stream"); if (stream_->close()) { stats.streams_closed_.inc(); } - stream_.reset(); + // Erase this entry from the map; this will also reset the stream_ pointer. + parent.erase(stream_.get()); } else { ENVOY_LOG(debug, "Stream already closed"); } - - // Erase this entry from the map. - parent.erase(stream_id); } // In the deferred closure mode, stream closure is deferred upon filter destruction, with a timer // to prevent unbounded resource usage growth. -void DeferredDeletableStream::deferredClose(Envoy::Event::Dispatcher& dispatcher, - uint64_t stream_id) { - derferred_close_timer = - dispatcher.createTimer([this, stream_id] { closeStreamOnTimer(stream_id); }); +void DeferredDeletableStream::deferredClose(Envoy::Event::Dispatcher& dispatcher) { + derferred_close_timer = dispatcher.createTimer([this] { closeStreamOnTimer(); }); derferred_close_timer->enableTimer(std::chrono::milliseconds(deferred_close_timeout)); } diff --git a/source/extensions/filters/http/ext_proc/ext_proc.h b/source/extensions/filters/http/ext_proc/ext_proc.h index b798a29b5f82..070b60b58d8e 100644 --- a/source/extensions/filters/http/ext_proc/ext_proc.h +++ b/source/extensions/filters/http/ext_proc/ext_proc.h @@ -158,9 +158,9 @@ struct DeferredDeletableStream : public Logger::Loggable { : stream_(std::move(stream)), parent(stream_manager), stats(stat), deferred_close_timeout(timeout) {} - void deferredClose(Envoy::Event::Dispatcher& dispatcher, uint64_t stream_id); + void deferredClose(Envoy::Event::Dispatcher& dispatcher); + void closeStreamOnTimer(); - void closeStreamOnTimer(uint64_t stream_id); ExternalProcessorStreamPtr stream_; ThreadLocalStreamManager& parent; ExtProcFilterStats stats; @@ -174,28 +174,28 @@ class ThreadLocalStreamManager : public Envoy::ThreadLocal::ThreadLocalObject { public: // Store the ExternalProcessorStreamPtr (as a wrapper object) in the map and return the raw // pointer of ExternalProcessorStream. - ExternalProcessorStream* store(uint64_t stream_id, ExternalProcessorStreamPtr stream, - const ExtProcFilterStats& stat, + ExternalProcessorStream* store(ExternalProcessorStreamPtr stream, const ExtProcFilterStats& stat, const std::chrono::milliseconds& timeout) { - stream_manager_[stream_id] = + auto deferred_stream = std::make_unique(std::move(stream), *this, stat, timeout); - return stream_manager_[stream_id]->stream_.get(); + ExternalProcessorStream* raw_stream = deferred_stream->stream_.get(); + stream_manager_[raw_stream] = std::move(deferred_stream); + return stream_manager_[raw_stream]->stream_.get(); } - void erase(uint64_t stream_id) { stream_manager_.erase(stream_id); } - - void deferredErase(uint64_t stream_id, Envoy::Event::Dispatcher& dispatcher) { - auto it = stream_manager_.find(stream_id); + void erase(ExternalProcessorStream* stream) { stream_manager_.erase(stream); } + void deferredErase(ExternalProcessorStream* stream, Envoy::Event::Dispatcher& dispatcher) { + auto it = stream_manager_.find(stream); if (it == stream_manager_.end()) { return; } - it->second->deferredClose(dispatcher, stream_id); + it->second->deferredClose(dispatcher); } private: - // Map of DeferredDeletableStreamPtrs with stream id as key. - absl::flat_hash_map stream_manager_; + // Map of DeferredDeletableStreamPtrs with ExternalProcessorStream pointer as key. + absl::flat_hash_map stream_manager_; }; class FilterConfig { diff --git a/source/extensions/filters/http/ext_proc/http_client/BUILD b/source/extensions/filters/http/ext_proc/http_client/BUILD new file mode 100644 index 000000000000..16afa5f69849 --- /dev/null +++ b/source/extensions/filters/http/ext_proc/http_client/BUILD @@ -0,0 +1,29 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "client_base_interface", + hdrs = ["client_base.h"], + tags = ["skip_on_windows"], + deps = [], +) + +envoy_cc_library( + name = "http_client_lib", + srcs = ["http_client_impl.cc"], + hdrs = ["http_client_impl.h"], + tags = ["skip_on_windows"], + deps = [ + "client_base_interface", + "//source/common/common:enum_to_int", + "//source/common/http:utility_lib", + "//source/extensions/filters/http/ext_proc", + ], +) diff --git a/source/extensions/filters/http/ext_proc/http_client/client_base.h b/source/extensions/filters/http/ext_proc/http_client/client_base.h new file mode 100644 index 000000000000..fd9ae5ce7c7f --- /dev/null +++ b/source/extensions/filters/http/ext_proc/http_client/client_base.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ExternalProcessing { + +/** + * Async callbacks used during external processing. + */ +class RequestCallbacks { +public: + virtual ~RequestCallbacks() = default; + virtual void onComplete() PURE; +}; + +/** + * Async client base class used during external processing. + */ +class ClientBase { +public: + virtual ~ClientBase() = default; + + virtual void sendRequest() PURE; + virtual void cancel() PURE; +}; + +} // namespace ExternalProcessing +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/ext_proc/http_client/http_client_impl.cc b/source/extensions/filters/http/ext_proc/http_client/http_client_impl.cc new file mode 100644 index 000000000000..abc172192389 --- /dev/null +++ b/source/extensions/filters/http/ext_proc/http_client/http_client_impl.cc @@ -0,0 +1,45 @@ +#include "source/extensions/filters/http/ext_proc/http_client/http_client_impl.h" + +#include "source/common/common/enum_to_int.h" +#include "source/common/http/utility.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ExternalProcessing { + +void ExtProcHttpClient::onSuccess(const Http::AsyncClient::Request&, + Http::ResponseMessagePtr&& response) { + auto status = Envoy::Http::Utility::getResponseStatusOrNullopt(response->headers()); + if (status.has_value()) { + uint64_t status_code = status.value(); + if (status_code == Envoy::enumToInt(Envoy::Http::Code::OK)) { + ENVOY_LOG(error, "Response status is OK"); + } else { + ENVOY_LOG(error, "Response status is not OK, status: {}", status_code); + onError(); + } + } else { + // This occurs if the response headers are invalid. + ENVOY_LOG(error, "Failed to get the response because response headers are not valid."); + onError(); + } +} + +void ExtProcHttpClient::onFailure(const Http::AsyncClient::Request&, + Http::AsyncClient::FailureReason reason) { + ASSERT(reason == Http::AsyncClient::FailureReason::Reset || + reason == Http::AsyncClient::FailureReason::ExceedResponseBufferLimit); + ENVOY_LOG(error, "Request failed: stream has been reset"); + onError(); +} + +void ExtProcHttpClient::onError() { + // Cancel if the request is active. + cancel(); +} + +} // namespace ExternalProcessing +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/ext_proc/http_client/http_client_impl.h b/source/extensions/filters/http/ext_proc/http_client/http_client_impl.h new file mode 100644 index 000000000000..fa2df5afd12d --- /dev/null +++ b/source/extensions/filters/http/ext_proc/http_client/http_client_impl.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "envoy/http/async_client.h" + +#include "source/common/common/logger.h" +#include "source/extensions/filters/http/ext_proc/ext_proc.h" +#include "source/extensions/filters/http/ext_proc/http_client/client_base.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ExternalProcessing { + +class ExtProcHttpClient : public ClientBase, + public Http::AsyncClient::Callbacks, + public Logger::Loggable { +public: + ExtProcHttpClient(const envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor& config, + Server::Configuration::ServerFactoryContext& context) + : config_(config), context_(context) {} + + ~ExtProcHttpClient() { cancel(); } + + void sendRequest() override {} + void cancel() override {} + void onBeforeFinalizeUpstreamSpan(Tracing::Span&, const Http::ResponseHeaderMap*) override {} + + // Http::AsyncClient::Callbacks implemented by this class. + void onSuccess(const Http::AsyncClient::Request& request, + Http::ResponseMessagePtr&& response) override; + void onFailure(const Http::AsyncClient::Request& request, + Http::AsyncClient::FailureReason reason) override; + + Server::Configuration::ServerFactoryContext& context() const { return context_; } + +private: + void onError(); + envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor config_; + Server::Configuration::ServerFactoryContext& context_; +}; + +} // namespace ExternalProcessing +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/file_system_buffer/filter.cc b/source/extensions/filters/http/file_system_buffer/filter.cc index c88198ad9173..a4e5e38f4295 100644 --- a/source/extensions/filters/http/file_system_buffer/filter.cc +++ b/source/extensions/filters/http/file_system_buffer/filter.cc @@ -67,13 +67,8 @@ Http::FilterHeadersStatus FileSystemBufferFilter::decodeHeaders(Http::RequestHea // the memory limit, once in our own buffer and once in the outgoing buffer. (Plus overflow // because the limit isn't hard.) request_callbacks_->setDecoderBufferLimit(request_state_.config_->memoryBufferBytesLimit()); - // If we're going to buffer everything, don't even start sending the data until we're ready. - if (request_state_.injecting_content_length_header_ || - request_state_.config_->behavior().alwaysFullyBuffer()) { - request_headers_ = &headers; - return Http::FilterHeadersStatus::StopIteration; - } - return Http::FilterHeadersStatus::Continue; + request_headers_ = &headers; + return Http::FilterHeadersStatus::StopIteration; } Http::FilterHeadersStatus FileSystemBufferFilter::encodeHeaders(Http::ResponseHeaderMap& headers, @@ -100,13 +95,8 @@ Http::FilterHeadersStatus FileSystemBufferFilter::encodeHeaders(Http::ResponseHe // the memory limit, once in our own buffer and once in the outgoing buffer. (Plus overflow // because the limit isn't hard.) response_callbacks_->setEncoderBufferLimit(response_state_.config_->memoryBufferBytesLimit()); - // If we're going to buffer everything, don't even start sending the data until we're ready. - if (response_state_.injecting_content_length_header_ || - response_state_.config_->behavior().alwaysFullyBuffer()) { - response_headers_ = &headers; - return Http::FilterHeadersStatus::StopIteration; - } - return Http::FilterHeadersStatus::Continue; + response_headers_ = &headers; + return Http::FilterHeadersStatus::StopIteration; } void FileSystemBufferFilter::onAboveWriteBufferHighWatermark() { diff --git a/source/extensions/filters/http/grpc_field_extraction/extractor.h b/source/extensions/filters/http/grpc_field_extraction/extractor.h index 4178e73fb090..d321b3651ec4 100644 --- a/source/extensions/filters/http/grpc_field_extraction/extractor.h +++ b/source/extensions/filters/http/grpc_field_extraction/extractor.h @@ -24,8 +24,8 @@ struct RequestField { // The request field path. absl::string_view path; - // The request field values. - std::vector values; + // The request field value. + ProtobufWkt::Value value; }; using ExtractionResult = std::vector; diff --git a/source/extensions/filters/http/grpc_field_extraction/extractor_impl.cc b/source/extensions/filters/http/grpc_field_extraction/extractor_impl.cc index adbaa44181bd..8470310aa09b 100644 --- a/source/extensions/filters/http/grpc_field_extraction/extractor_impl.cc +++ b/source/extensions/filters/http/grpc_field_extraction/extractor_impl.cc @@ -7,7 +7,6 @@ #include "source/common/common/logger.h" -#include "absl/strings/str_format.h" #include "proto_field_extraction/field_value_extractor/field_value_extractor_factory.h" #include "proto_field_extraction/field_value_extractor/field_value_extractor_interface.h" @@ -39,18 +38,14 @@ ExtractorImpl::processRequest(Protobuf::field_extraction::MessageData& message) ExtractionResult result; for (const auto& it : per_field_extractors_) { - auto extracted_values = it.second->Extract(message); - if (!extracted_values.ok()) { - return extracted_values.status(); + absl::StatusOr extracted_value = it.second->ExtractValue(message); + if (!extracted_value.ok()) { + return extracted_value.status(); } ENVOY_LOG_MISC(debug, "extracted the following resource values from the {} field: {}", it.first, - std::accumulate(extracted_values.value().begin(), extracted_values.value().end(), - std::string(), - [](const std::string& lhs, const std::string& rhs) { - return absl::StrFormat("%s, %s", lhs, rhs); - })); - result.push_back({it.first, std::move(extracted_values.value())}); + extracted_value->DebugString()); + result.push_back({it.first, std::move(*extracted_value)}); } return result; diff --git a/source/extensions/filters/http/grpc_field_extraction/filter.cc b/source/extensions/filters/http/grpc_field_extraction/filter.cc index fb66c448dffd..7ae1fb12f326 100644 --- a/source/extensions/filters/http/grpc_field_extraction/filter.cc +++ b/source/extensions/filters/http/grpc_field_extraction/filter.cc @@ -214,10 +214,7 @@ void Filter::handleExtractionResult(const ExtractionResult& result) { ProtobufWkt::Struct dest_metadata; for (const auto& req_field : result) { RELEASE_ASSERT(!req_field.path.empty(), "`req_field.path` shouldn't be empty"); - auto* list = (*dest_metadata.mutable_fields())[req_field.path].mutable_list_value(); - for (const auto& value : req_field.values) { - list->add_values()->set_string_value(value); - } + (*dest_metadata.mutable_fields())[req_field.path] = req_field.value; } if (dest_metadata.fields_size() > 0) { ENVOY_STREAM_LOG(debug, "injected dynamic metadata `{}` with `{}`", *decoder_callbacks_, diff --git a/source/extensions/filters/http/jwt_authn/matcher.cc b/source/extensions/filters/http/jwt_authn/matcher.cc index bab21c5441d4..1bdb41fabb9d 100644 --- a/source/extensions/filters/http/jwt_authn/matcher.cc +++ b/source/extensions/filters/http/jwt_authn/matcher.cc @@ -7,6 +7,7 @@ #include "source/common/common/matchers.h" #include "source/common/common/regex.h" #include "source/common/http/path_utility.h" +#include "source/common/protobuf/message_validator_impl.h" #include "source/common/router/config_impl.h" #include "absl/strings/match.h" @@ -188,6 +189,43 @@ class PathSeparatedPrefixMatcherImpl : public BaseMatcherImpl { }; } // namespace +class PathMatchPolicyMatcherImpl : public BaseMatcherImpl { +public: + PathMatchPolicyMatcherImpl(const RequirementRule& rule, + Server::Configuration::CommonFactoryContext& context) + : BaseMatcherImpl(rule, context), uri_template_matcher_(createUriTemplateMatcher(rule)) {} + + bool matches(const Http::RequestHeaderMap& headers) const override { + if (BaseMatcherImpl::matchRoute(headers) && + uri_template_matcher_->match(headers.getPathValue())) { + ENVOY_LOG(debug, "Path match policy requirement '{}' matched.", + uri_template_matcher_->uriTemplate()); + return true; + } + + return false; + } + +private: + const Router::PathMatcherSharedPtr uri_template_matcher_; + + static Router::PathMatcherSharedPtr createUriTemplateMatcher(const RequirementRule& rule) { + auto& factory = Config::Utility::getAndCheckFactory( + rule.match().path_match_policy()); + ProtobufTypes::MessagePtr config = Envoy::Config::Utility::translateAnyToFactoryConfig( + rule.match().path_match_policy().typed_config(), + ProtobufMessage::getStrictValidationVisitor(), factory); + + absl::StatusOr matcher = factory.createPathMatcher(*config); + + if (!matcher.ok()) { + throw EnvoyException(std::string(matcher.status().message())); + } + + return matcher.value(); + } +}; + MatcherConstPtr Matcher::create(const RequirementRule& rule, Server::Configuration::CommonFactoryContext& context) { switch (rule.match().path_specifier_case()) { @@ -201,10 +239,9 @@ MatcherConstPtr Matcher::create(const RequirementRule& rule, return std::make_unique(rule, context); case RouteMatch::PathSpecifierCase::kPathSeparatedPrefix: return std::make_unique(rule, context); - case RouteMatch::PathSpecifierCase::kPathMatchPolicy: - // TODO(silverstar194): Implement matcher for template based match - throw EnvoyException("RouteMatch: path_match_policy is not supported"); - break; + case RouteMatch::PathSpecifierCase::kPathMatchPolicy: { + return std::make_unique(rule, context); + } case RouteMatch::PathSpecifierCase::PATH_SPECIFIER_NOT_SET: break; // Fall through to PANIC. } diff --git a/source/extensions/filters/http/match_delegate/config.cc b/source/extensions/filters/http/match_delegate/config.cc index e944c7b47bcb..5651c9ca8f40 100644 --- a/source/extensions/filters/http/match_delegate/config.cc +++ b/source/extensions/filters/http/match_delegate/config.cc @@ -312,7 +312,7 @@ absl::StatusOr MatchDelegateConfig::createFilterFa auto message = Config::Utility::translateAnyToFactoryConfig( proto_config.extension_config().typed_config(), validation, factory); auto filter_factory_or_error = factory.createFilterFactoryFromProto(*message, prefix, context); - RETURN_IF_STATUS_NOT_OK(filter_factory_or_error); + RETURN_IF_NOT_OK_REF(filter_factory_or_error.status()); auto filter_factory = filter_factory_or_error.value(); Factory::MatchTreeValidationVisitor validation_visitor(*factory.matchingRequirements()); diff --git a/source/extensions/filters/http/oauth2/filter.cc b/source/extensions/filters/http/oauth2/filter.cc index fa854156d456..77e2496f2234 100644 --- a/source/extensions/filters/http/oauth2/filter.cc +++ b/source/extensions/filters/http/oauth2/filter.cc @@ -41,6 +41,7 @@ Http::RegisterCustomInlineHeadercookieDomain().empty()) { + cookie_tail_http_only = absl::StrCat( + fmt::format(CookieDomainFormatString, config_->cookieDomain()), cookie_tail_http_only); + } + const CookieNames& cookie_names = config_->cookieNames(); headers.addReferenceKey( diff --git a/source/extensions/filters/http/oauth2/filter.h b/source/extensions/filters/http/oauth2/filter.h index 4075869ed5ff..7ba18e318b00 100644 --- a/source/extensions/filters/http/oauth2/filter.h +++ b/source/extensions/filters/http/oauth2/filter.h @@ -141,6 +141,7 @@ class FilterConfig { FilterStats& stats() { return stats_; } const std::string& encodedResourceQueryParams() const { return encoded_resource_query_params_; } const CookieNames& cookieNames() const { return cookie_names_; } + const std::string& cookieDomain() const { return cookie_domain_; } const AuthType& authType() const { return auth_type_; } bool useRefreshToken() const { return use_refresh_token_; } std::chrono::seconds defaultExpiresIn() const { return default_expires_in_; } @@ -168,6 +169,7 @@ class FilterConfig { const std::vector pass_through_header_matchers_; const std::vector deny_redirect_header_matchers_; const CookieNames cookie_names_; + const std::string cookie_domain_; const AuthType auth_type_; const std::chrono::seconds default_expires_in_; const std::chrono::seconds default_refresh_token_expires_in_; diff --git a/source/extensions/filters/http/proto_message_logging/logging_util/BUILD b/source/extensions/filters/http/proto_message_logging/logging_util/BUILD new file mode 100644 index 000000000000..6396b1a4d572 --- /dev/null +++ b/source/extensions/filters/http/proto_message_logging/logging_util/BUILD @@ -0,0 +1,41 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "proto_scrubber_interface", + hdrs = [ + "proto_scrubber_interface.h", + ], + deps = [ + "//source/common/protobuf", + "//source/common/protobuf:cc_wkt_protos", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_protofieldextraction//:all_libs", + ], +) + +envoy_cc_library( + name = "logging_util", + srcs = [ + "logging_util.cc", + ], + hdrs = [ + "logging_util.h", + ], + deps = [ + ":proto_scrubber_interface", + "//source/common/common:regex_lib", + "//source/common/protobuf", + "//source/common/protobuf:cc_wkt_protos", + "@com_google_protoconverter//:all", + "@com_google_protofieldextraction//:all_libs", + "@com_google_protoprocessinglib//proto_processing_lib/proto_scrubber", + ], +) diff --git a/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.cc b/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.cc new file mode 100644 index 000000000000..55abc9b7e8c2 --- /dev/null +++ b/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.cc @@ -0,0 +1,419 @@ +#include "source/extensions/filters/http/proto_message_logging/logging_util/logging_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "source/common/protobuf/protobuf.h" + +#include "absl/container/flat_hash_map.h" +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/match.h" +#include "absl/strings/str_replace.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "absl/types/span.h" +#include "proto_field_extraction/field_extractor/field_extractor.h" +#include "proto_field_extraction/message_data/message_data.h" +#include "proto_processing_lib/proto_scrubber/proto_scrubber.h" +#include "src/google/protobuf/util/converter/error_listener.h" +#include "src/google/protobuf/util/converter/json_objectwriter.h" +#include "src/google/protobuf/util/converter/json_stream_parser.h" +#include "src/google/protobuf/util/converter/object_source.h" +#include "src/google/protobuf/util/converter/object_writer.h" +#include "src/google/protobuf/util/converter/protostream_objectsource.h" +#include "src/google/protobuf/util/converter/protostream_objectwriter.h" +#include "src/google/protobuf/util/converter/type_info.h" +#include "src/google/protobuf/util/converter/utility.h" +#include "src/google/protobuf/util/field_mask_util.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ProtoMessageLogging { + +namespace { + +using ::Envoy::Protobuf::Field; +using ::Envoy::Protobuf::Map; +using ::Envoy::Protobuf::Type; +using ::Envoy::Protobuf::field_extraction::FieldExtractor; +using ::Envoy::Protobuf::internal::WireFormatLite; +using ::Envoy::Protobuf::io::CodedInputStream; +using ::Envoy::Protobuf::io::CordOutputStream; +using ::Envoy::Protobuf::util::JsonParseOptions; +using ::Envoy::Protobuf::util::TypeResolver; +using ::Envoy::Protobuf::util::converter::GetFullTypeWithUrl; +using ::Envoy::Protobuf::util::converter::JsonObjectWriter; +using ::Envoy::Protobuf::util::converter::ProtoStreamObjectSource; +using ::Envoy::ProtobufWkt::Struct; +using ::Envoy::ProtobufWkt::Value; +using ::proto_processing_lib::proto_scrubber::ProtoScrubber; + +std::string kLocationRegionExtractorPattern = R"((?:^|/)(?:locations|regions)/([^/]+))"; + +} // namespace + +// Returns true if the given Struct only contains a "@type" field. +bool IsEmptyStruct(const Struct& message_struct) { + return message_struct.fields_size() == 1 && + message_struct.fields().cbegin()->first == kTypeProperty; +} + +bool IsLabelName(absl::string_view value) { + return absl::StartsWith(value, "{") && absl::EndsWith(value, "}"); +} + +// Monitored resource label names are captured within curly brackets ("{", "}"). +// The format is verified by the service config validator, so to extract label +// name, we just remove the brackets. +std::string GetLabelName(absl::string_view value) { + return absl::StrReplaceAll(value, {{"{", ""}, {"}", ""}}); +} + +// Singleton mapping of string to AuditDirective. +const absl::flat_hash_map& StringToDirectiveMap() { + static auto* string_to_directive_map = new absl::flat_hash_map({ + {kAuditRedact, AuditDirective::AUDIT_REDACT}, + {kAudit, AuditDirective::AUDIT}, + }); + return *string_to_directive_map; +} + +absl::optional AuditDirectiveFromString(absl::string_view directive) { + if (StringToDirectiveMap().contains(directive)) { + return StringToDirectiveMap().at(directive); + } + return std::nullopt; +} + +// Returns a mapping of monitored resource label keys to their values. +void GetMonitoredResourceLabels(absl::string_view label_extractor, + absl::string_view resource_string, + Map* labels) { + // The monitored resource label extractor is formatted as + // "project/*/bucket/{bucket}/object/{object}", where label names are + // surrounded by {}. + std::vector pattern_split = + absl::StrSplit(label_extractor, '/', absl::SkipEmpty()); + std::vector resource_split = + absl::StrSplit(resource_string, '/', absl::SkipEmpty()); + // Note that pattern_split and resource_split sizes can vary, since it's + // possible for certain APIs, IE. List APIs, some resource labels may + // naturally be missing. + // + // Iterate over both patternSplit and resourceSplit at the same time, stopping + // when the index exceeds either ranges. + int min_size = std::min(pattern_split.size(), resource_split.size()); + for (int index = 0; index < min_size; ++index) { + if (IsLabelName(pattern_split[index])) { + (*labels)[GetLabelName(pattern_split[index])] = std::string(resource_split[index]); + } + } +} + +WireFormatLite::WireType GetWireType(const Field& field_desc) { + static WireFormatLite::WireType field_kind_to_wire_type[] = { + static_cast(-1), // TYPE_UNKNOWN + WireFormatLite::WIRETYPE_FIXED64, // TYPE_DOUBLE + WireFormatLite::WIRETYPE_FIXED32, // TYPE_FLOAT + WireFormatLite::WIRETYPE_VARINT, // TYPE_INT64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_INT32 + WireFormatLite::WIRETYPE_FIXED64, // TYPE_FIXED64 + WireFormatLite::WIRETYPE_FIXED32, // TYPE_FIXED32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_BOOL + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_STRING + WireFormatLite::WIRETYPE_START_GROUP, // TYPE_GROUP + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_MESSAGE + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_BYTES + WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_ENUM + WireFormatLite::WIRETYPE_FIXED32, // TYPE_SFIXED32 + WireFormatLite::WIRETYPE_FIXED64, // TYPE_SFIXED64 + WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT32 + WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT64 + }; + return field_kind_to_wire_type[field_desc.kind()]; +} + +absl::StatusOr +ExtractRepeatedFieldSizeHelper(const FieldExtractor& field_extractor, const std::string& path, + const Protobuf::field_extraction::MessageData& message) { + if (path.empty()) { + return absl::InvalidArgumentError("Field mask path cannot be empty."); + } + + auto extract_func = [](const Type& /*enclosing_type*/, const Field* field, + CodedInputStream* input_stream) -> absl::StatusOr { + if (field->cardinality() != Field::CARDINALITY_REPEATED) { + return absl::InvalidArgumentError( + absl::Substitute("Field '$0' is not a repeated or map field.", field->name())); + } + + // repeated field or map field. + uint32_t count = 0, tag = 0; + if (field->packed()) { + const WireFormatLite::WireType field_wire_type = GetWireType(*field); + + while ((tag = input_stream->ReadTag()) != 0) { + if (field->number() != WireFormatLite::GetTagFieldNumber(tag)) { + WireFormatLite::SkipField(input_stream, tag); + } else { + DCHECK_EQ(WireFormatLite::WIRETYPE_LENGTH_DELIMITED, WireFormatLite::GetTagWireType(tag)); + + uint32_t length; + input_stream->ReadVarint32(&length); + if (field->kind() == Field::TYPE_BOOL) { + count += length / WireFormatLite::kBoolSize; + input_stream->Skip(length); + } else if (field_wire_type == WireFormatLite::WIRETYPE_FIXED32) { + count += length / WireFormatLite::kFixed32Size; + input_stream->Skip(length); + } else if (field_wire_type == WireFormatLite::WIRETYPE_FIXED64) { + count += length / WireFormatLite::kFixed64Size; + input_stream->Skip(length); + } else { + CodedInputStream::Limit limit = input_stream->PushLimit(length); + uint64_t varint = 0; + while (input_stream->ReadVarint64(&varint)) { + ++count; + } + input_stream->PopLimit(limit); + } + } + } + } else { // not packed. + while ((tag = input_stream->ReadTag()) != 0) { + if (field->number() == WireFormatLite::GetTagFieldNumber(tag)) { + ++count; + } + WireFormatLite::SkipField(input_stream, tag); + } + } + return count; + }; + + Protobuf::field_extraction::MessageData& msg( + const_cast(message)); + + return field_extractor.ExtractFieldInfo(path, msg.CreateCodedInputStreamWrapper()->Get(), + extract_func); +} + +int64_t ExtractRepeatedFieldSize(const Type& type, + std::function type_finder, + const Protobuf::FieldMask* field_mask, + const Protobuf::field_extraction::MessageData& message) { + int64_t num_response_items = -1LL; + if (field_mask == nullptr || field_mask->paths_size() < 1) { + return num_response_items; + } + + // AUDIT_SIZE directive should only be applied to one field. Tools + // framework validation should check this case. + DCHECK_EQ(1, field_mask->paths_size()); + + FieldExtractor field_extractor(&type, std::move(type_finder)); + absl::StatusOr status_or_size = + ExtractRepeatedFieldSizeHelper(field_extractor, field_mask->paths(0), message); + if (!status_or_size.ok()) { + LOG(WARNING) << "Failed to extract repeated field size of '" << field_mask->paths(0) + << "' from proto '" << type.name() << "': " << status_or_size.status(); + } else { + num_response_items = *status_or_size; + } + return num_response_items; +} + +absl::string_view ExtractLocationIdFromResourceName(absl::string_view resource_name) { + absl::string_view location; + RE2::PartialMatch(resource_name, kLocationRegionExtractorPattern, &location); + return location; +} + +// Recursively redacts the path_pieces in the enclosing proto_struct. +void RedactPath(std::vector::const_iterator path_begin, + std::vector::const_iterator path_end, Struct* proto_struct) { + if (path_begin == path_end) { + proto_struct->Clear(); + return; + } + + const std::string& field = *path_begin; + path_begin++; + + auto* struct_fields = proto_struct->mutable_fields(); + // Return if any piece of the path wasn't populated. + auto field_it = struct_fields->find(field); + if (field_it == struct_fields->end()) { + return; + } + + // Handle repeated field. We allow redacting repeated leaf and non-leaf + // message type fields. + auto& field_value = field_it->second; + if (field_value.has_list_value()) { + auto* repeated_values = field_value.mutable_list_value()->mutable_values(); + for (int i = 0; i < repeated_values->size(); ++i) { + Value* value = repeated_values->Mutable(i); + CHECK(value->has_struct_value()) << "Cannot redact non-message-type field " << field; + RedactPath(path_begin, path_end, value->mutable_struct_value()); + } + return; + } + + // Fail if trying to redact non-message-type field. + CHECK(field_value.has_struct_value()) << "Cannot redact non-message-type field " << field; + RedactPath(path_begin, path_end, field_value.mutable_struct_value()); +} + +void RedactPaths(absl::Span paths_to_redact, Struct* proto_struct) { + for (const std::string& path : paths_to_redact) { + std::vector path_pieces = absl::StrSplit(path, '.', absl::SkipEmpty()); + CHECK(path_pieces.size() < kMaxRedactedPathDepth) + << "Attempting to redact path with depth >= " << kMaxRedactedPathDepth << ": " << path; + RedactPath(path_pieces.begin(), path_pieces.end(), proto_struct); + } +} + +// Finds the last value of the non-repeated string field after the first value. +// Returns an empty string if there is only one string field. Returns an error +// if the resource is malformed in case that the search goes forever. +absl::StatusOr FindSingularLastValue(const Field* field, + CodedInputStream* input_stream) { + std::string resource; + int position = input_stream->CurrentPosition(); + while (FieldExtractor::SearchField(*field, input_stream)) { + if (input_stream->CurrentPosition() == position) { + return absl::InvalidArgumentError( + "The request message is malformed with endless values for a single field."); + } + position = input_stream->CurrentPosition(); + if (field->kind() == Field::TYPE_STRING) { + WireFormatLite::ReadString(input_stream, &resource); + } + } + return resource; +} + +// Non-repeated fields can be repeat in a wire-format, in that case use the last +// value. +// +// Quote from the go/proto-encoding: +// "Normally, an encoded message would never have more than one instance of a +// non-repeated field. However, parsers are expected to handle the case in which +// they do." +absl::StatusOr SingularFieldUseLastValue(const std::string first_value, + const Field* field, + CodedInputStream* input_stream) { + ASSIGN_OR_RETURN(std::string last_value, FindSingularLastValue(field, input_stream)); + if (last_value.empty()) + return first_value; + return last_value; +} + +absl::StatusOr ExtractStringFieldValue( + const Type& type, std::function type_finder, + const std::string& path, const Protobuf::field_extraction::MessageData& message) { + if (path.empty()) { + return absl::InvalidArgumentError("Field mask path cannot be empty."); + } + + auto extract_func = [](const Type& /*enclosing_type*/, const Field* field, + CodedInputStream* input_stream) -> absl::StatusOr { + if (field->kind() != Field::TYPE_STRING) { + return absl::InvalidArgumentError( + absl::Substitute("Field '$0' is not a singular string field.", field->name())); + } else if (field->cardinality() == Field::CARDINALITY_REPEATED) { + return absl::InvalidArgumentError( + absl::Substitute("Field '$0' is a repeated string field, only singular " + "string field is accepted.", + field->name())); + } else { // singular string field + std::string result; + if (FieldExtractor::SearchField(*field, input_stream)) { + uint32_t length; + input_stream->ReadVarint32(&length); + input_stream->ReadString(&result, length); + } + + ASSIGN_OR_RETURN(result, SingularFieldUseLastValue(result, field, input_stream)); + + return result; + } + }; + + FieldExtractor field_extractor(&type, std::move(type_finder)); + return field_extractor.ExtractFieldInfo( + path, message.CreateCodedInputStreamWrapper()->Get(), extract_func); +} + +absl::Status RedactStructRecursively(std::vector::const_iterator path_pieces_begin, + std::vector::const_iterator path_pieces_end, + Struct* message_struct) { + if (message_struct == nullptr) { + return absl::InvalidArgumentError("message_struct cannot be nullptr."); + } + if (path_pieces_begin == path_pieces_end) { + return absl::OkStatus(); + } + + const std::string& current_piece = *path_pieces_begin; + if (current_piece.empty()) { + return absl::InvalidArgumentError("path piece cannot be empty."); + } + + auto* fields = message_struct->mutable_fields(); + auto iter = fields->find(current_piece); + if (iter == fields->end()) { + // Add empty struct. + (*fields)[current_piece].mutable_struct_value(); + } else if (!iter->second.has_struct_value()) { + return absl::InvalidArgumentError("message_struct cannot be nullptr."); + } + return RedactStructRecursively(++path_pieces_begin, path_pieces_end, + (*fields)[current_piece].mutable_struct_value()); +} + +absl::StatusOr +IsMessageFieldPathPresent(const Protobuf::Type& type, + std::function type_finder, + const std::string& path, + const Protobuf::field_extraction::MessageData& message) { + if (path.empty()) { + return absl::InvalidArgumentError("Field path cannot be empty."); + } + + auto extract_func = [](const Type& /*enclosing_type*/, const Field* field, + CodedInputStream* input_stream) -> absl::StatusOr { + if (field->kind() != Field::TYPE_MESSAGE) { + return absl::InvalidArgumentError( + absl::Substitute("Field '$0' is not a message type field.", field->name())); + } else if (field->cardinality() == Field::CARDINALITY_REPEATED) { + return absl::InvalidArgumentError( + absl::Substitute("Field '$0' is not a singular field.", field->name())); + } else { // singular message field + return FieldExtractor::SearchField(*field, input_stream); + } + }; + + FieldExtractor field_extractor(&type, std::move(type_finder)); + Protobuf::field_extraction::MessageData& msg( + const_cast(message)); + return field_extractor.ExtractFieldInfo(path, msg.CreateCodedInputStreamWrapper()->Get(), + extract_func); +} +} // namespace ProtoMessageLogging +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.h b/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.h new file mode 100644 index 000000000000..d826a3c55cd2 --- /dev/null +++ b/source/extensions/filters/http/proto_message_logging/logging_util/logging_util.h @@ -0,0 +1,130 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "source/common/protobuf/protobuf.h" +#include "source/extensions/filters/http/proto_message_logging/logging_util/proto_scrubber_interface.h" + +#include "absl/base/attributes.h" +#include "absl/container/flat_hash_map.h" +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "google/api/monitored_resource.pb.h" +#include "proto_field_extraction/field_extractor/field_extractor.h" +#include "proto_field_extraction/message_data/message_data.h" +#include "proto_processing_lib/proto_scrubber/proto_scrubber.h" +#include "re2/re2.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ProtoMessageLogging { + +// The type property value that will be included into the converted Struct. +constexpr char kTypeProperty[] = "@type"; + +ABSL_CONST_INIT const char* const kTypeServiceBaseUrl = "type.googleapis.com"; + +constexpr char kAuditRedact[] = "AUDIT_REDACT"; + +constexpr char kAudit[] = "AUDIT"; + +constexpr int kMaxRedactedPathDepth = 10; + +constexpr int kProtoTranslationMaxRecursionDepth = 64; + +ABSL_CONST_INIT const char* const kStructTypeUrl = "type.googleapis.com/google.protobuf.Struct"; + +// class proto_processing_lib::proto_scrubber::ProtoScrubber; + +bool IsEmptyStruct(const ProtobufWkt::Struct& message_struct); + +bool IsLabelName(absl::string_view value); + +// Monitored resource label names are captured within curly brackets ("{", "}"). +// The format is verified by the service config validator, so to extract label +// name, we just remove the brackets. +std::string GetLabelName(absl::string_view value); + +// Singleton mapping of string to AuditDirective. +const absl::flat_hash_map& StringToDirectiveMap(); + +absl::optional AuditDirectiveFromString(absl::string_view directive); + +// Returns a mapping of monitored resource label keys to their values. +void GetMonitoredResourceLabels(absl::string_view label_extractor, + absl::string_view resource_string, + Protobuf::Map* labels); + +// Returns the size of the repeated field represented by given field mask from +// given raw message. +// +// In case of error or nullptr/empty field_mask, it returns a negative value and +// logs the error. +int64_t +ExtractRepeatedFieldSize(const Protobuf::Type& type, + std::function type_finder, + const Protobuf::FieldMask* field_mask, + const Protobuf::field_extraction::MessageData& message); + +// Extract the size of the repeated field represented by given field mask +// path from given proto message. `path` must represent a repeated field. +absl::StatusOr +ExtractRepeatedFieldSizeHelper(const Protobuf::field_extraction::FieldExtractor& field_extractor, + const std::string& path, + const Protobuf::field_extraction::MessageData& message); + +absl::string_view ExtractLocationIdFromResourceName(absl::string_view resource_name); + +// Recursively redacts the path_pieces in the enclosing proto_struct. +void RedactPath(std::vector::const_iterator path_begin, + std::vector::const_iterator path_end, + ProtobufWkt::Struct* proto_struct); + +void RedactPaths(absl::Span paths_to_redact, ProtobufWkt::Struct* proto_struct); + +// Finds the last value of the non-repeated string field after the first +// value. Returns an empty string if there is only one string field. Returns +// an error if the resource is malformed in case that the search goes forever. +absl::StatusOr +FindSingularLastValue(const Protobuf::Field* field, + Envoy::Protobuf::io::CodedInputStream* input_stream); + +// Non-repeated fields can be repeat in a wire-format, in that case use the +// last value. +// +// "Normally, an encoded message would never have more than one instance of a +// non-repeated field. However, parsers are expected to handle the case in +// which they do." +absl::StatusOr +SingularFieldUseLastValue(const std::string first_value, const Protobuf::Field* field, + Envoy::Protobuf::io::CodedInputStream* input_stream); + +absl::StatusOr +ExtractStringFieldValue(const Protobuf::Type& type, + std::function type_finder, + const std::string& path, + const Protobuf::field_extraction::MessageData& message); + +absl::Status RedactStructRecursively(std::vector::const_iterator path_pieces_begin, + std::vector::const_iterator path_pieces_end, + ProtobufWkt::Struct* message_struct); + +absl::StatusOr +IsMessageFieldPathPresent(const Protobuf::Type& type, + std::function type_finder, + const std::string& path, + const Protobuf::field_extraction::MessageData& message); + +} // namespace ProtoMessageLogging +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/proto_message_logging/logging_util/proto_scrubber_interface.h b/source/extensions/filters/http/proto_message_logging/logging_util/proto_scrubber_interface.h new file mode 100644 index 000000000000..cb890634c1bf --- /dev/null +++ b/source/extensions/filters/http/proto_message_logging/logging_util/proto_scrubber_interface.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include + +#include "source/common/protobuf/protobuf.h" + +#include "absl/container/flat_hash_map.h" +#include "proto_field_extraction/message_data/message_data.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ProtoMessageLogging { + +// All valid field auditing directives for Cloud Audit Logging. +enum class AuditDirective { + AUDIT_REDACT, + AUDIT, +}; + +using FieldPathToScrubType = absl::flat_hash_map>; + +// Metadata that can be captured during message scrubbing. +struct AuditMetadata { + absl::optional num_response_items; + absl::optional target_resource; + absl::optional target_resource_callback; + absl::optional resource_location; + ProtobufWkt::Struct scrubbed_message; +}; + +// A proto-scrubbing interface for audit logging that converts a source message +// to a proto Struct. +class ProtoScrubberInterface { +public: + // Scrubs the message for auditing, then populates and returns AuditMetadata + // that contains the scrubbed message and other audit metadata obtained during + // scrubbing. + virtual AuditMetadata + ScrubMessage(const Protobuf::field_extraction::MessageData& message) const = 0; + + // Returns the message type this scrubber will handle, without the + // type url prefix "type.googleapis.com". + virtual const std::string& MessageType() const = 0; + + virtual ~ProtoScrubberInterface() = default; +}; + +} // namespace ProtoMessageLogging +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/http/rate_limit_quota/client_impl.cc b/source/extensions/filters/http/rate_limit_quota/client_impl.cc index b51e5725fda1..f454695b55bc 100644 --- a/source/extensions/filters/http/rate_limit_quota/client_impl.cc +++ b/source/extensions/filters/http/rate_limit_quota/client_impl.cc @@ -64,10 +64,14 @@ RateLimitQuotaUsageReports RateLimitClientImpl::buildReport(absl::optional bucket_id) { - ASSERT(stream_ != nullptr); - // Build the report and then send the report to RLQS server. - // `end_stream` should always be set to false as we don't want to close the stream locally. - stream_->sendMessage(buildReport(bucket_id), /*end_stream=*/false); + if (stream_ != nullptr) { + // Build the report and then send the report to RLQS server. + // `end_stream` should always be set to false as we don't want to close the stream locally. + stream_->sendMessage(buildReport(bucket_id), /*end_stream=*/false); + } else { + // Don't send any reports if stream has already been closed. + ENVOY_LOG(debug, "The stream has already been closed; no reports will be sent."); + } } void RateLimitClientImpl::onReceiveMessage(RateLimitQuotaResponsePtr&& response) { @@ -143,20 +147,18 @@ void RateLimitClientImpl::onReceiveMessage(RateLimitQuotaResponsePtr&& response) void RateLimitClientImpl::closeStream() { // Close the stream if it is in open state. - if (stream_ != nullptr && !stream_closed_) { + if (stream_ != nullptr) { ENVOY_LOG(debug, "Closing gRPC stream"); stream_->closeStream(); - stream_closed_ = true; stream_->resetStream(); + stream_ = nullptr; } } void RateLimitClientImpl::onRemoteClose(Grpc::Status::GrpcStatus status, const std::string& message) { - // TODO(tyxia) Revisit later, maybe add some logging. - stream_closed_ = true; ENVOY_LOG(debug, "gRPC stream closed remotely with status {}: {}", status, message); - closeStream(); + stream_ = nullptr; } absl::Status RateLimitClientImpl::startStream(const StreamInfo::StreamInfo& stream_info) { diff --git a/source/extensions/filters/http/rate_limit_quota/client_impl.h b/source/extensions/filters/http/rate_limit_quota/client_impl.h index 4999ef62f9ca..b471755d2420 100644 --- a/source/extensions/filters/http/rate_limit_quota/client_impl.h +++ b/source/extensions/filters/http/rate_limit_quota/client_impl.h @@ -58,8 +58,6 @@ class RateLimitClientImpl : public RateLimitClient, // Build the usage report (i.e., the request sent to RLQS server) from the buckets in quota bucket // cache. RateLimitQuotaUsageReports buildReport(absl::optional bucket_id); - - bool stream_closed_ = false; // Domain from filter configuration. The same domain name throughout the whole lifetime of client. std::string domain_name_; // Client is stored as the bare object since there is no ownership transfer involved. diff --git a/source/extensions/filters/http/rate_limit_quota/filter.cc b/source/extensions/filters/http/rate_limit_quota/filter.cc index 28600208658c..7cbb29fcdb4f 100644 --- a/source/extensions/filters/http/rate_limit_quota/filter.cc +++ b/source/extensions/filters/http/rate_limit_quota/filter.cc @@ -9,6 +9,8 @@ namespace Extensions { namespace HttpFilters { namespace RateLimitQuota { +const char kBucketMetadataNamespace[] = "envoy.extensions.http_filters.rate_limit_quota.bucket"; + Http::FilterHeadersStatus RateLimitQuotaFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) { ENVOY_LOG(trace, "decodeHeaders: end_stream = {}", end_stream); @@ -28,7 +30,8 @@ Http::FilterHeadersStatus RateLimitQuotaFilter::decodeHeaders(Http::RequestHeade // succeeds. const RateLimitOnMatchAction& match_action = match_result.value()->getTyped(); - auto ret = match_action.generateBucketId(*data_ptr_, factory_context_, visitor_); + absl::StatusOr ret = + match_action.generateBucketId(*data_ptr_, factory_context_, visitor_); if (!ret.ok()) { // When it failed to generate the bucket id for this specific request, the request is ALLOWED by // default (i.e., fail-open). @@ -36,19 +39,26 @@ Http::FilterHeadersStatus RateLimitQuotaFilter::decodeHeaders(Http::RequestHeade return Envoy::Http::FilterHeadersStatus::Continue; } - BucketId bucket_id_proto = ret.value(); + const BucketId& bucket_id_proto = *ret; const size_t bucket_id = MessageUtil::hash(bucket_id_proto); ENVOY_LOG(trace, "Generated the associated hashed bucket id: {} for bucket id proto:\n {}", bucket_id, bucket_id_proto.DebugString()); + + ProtobufWkt::Struct bucket_log; + auto* bucket_log_fields = bucket_log.mutable_fields(); + for (const auto& bucket : bucket_id_proto.bucket()) + (*bucket_log_fields)[bucket.first] = ValueUtil::stringValue(bucket.second); + + callbacks_->streamInfo().setDynamicMetadata(kBucketMetadataNamespace, bucket_log); + if (quota_buckets_.find(bucket_id) == quota_buckets_.end()) { // For first matched request, create a new bucket in the cache and sent the report to RLQS // server immediately. createNewBucket(bucket_id_proto, match_action, bucket_id); return sendImmediateReport(bucket_id, match_action); - } else { - // Found the cached bucket entry. - return processCachedBucket(bucket_id, match_action); } + + return processCachedBucket(bucket_id, match_action); } void RateLimitQuotaFilter::createMatcher() { diff --git a/source/extensions/filters/http/ratelimit/BUILD b/source/extensions/filters/http/ratelimit/BUILD index fd4c15c81ace..6d56028db50d 100644 --- a/source/extensions/filters/http/ratelimit/BUILD +++ b/source/extensions/filters/http/ratelimit/BUILD @@ -20,11 +20,13 @@ envoy_cc_library( ":ratelimit_headers_lib", "//envoy/http:codes_interface", "//envoy/ratelimit:ratelimit_interface", + "//envoy/stream_info:uint32_accessor_interface", "//source/common/common:assert_lib", "//source/common/common:empty_string", "//source/common/common:enum_to_int", "//source/common/http:codes_lib", "//source/common/router:config_lib", + "//source/common/stream_info:uint32_accessor_lib", "//source/extensions/filters/common/ratelimit:ratelimit_client_interface", "//source/extensions/filters/common/ratelimit:stat_names_lib", "@envoy_api//envoy/extensions/filters/http/ratelimit/v3:pkg_cc_proto", diff --git a/source/extensions/filters/http/ratelimit/ratelimit.cc b/source/extensions/filters/http/ratelimit/ratelimit.cc index 382029e5f3db..7052f8f793ed 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.cc +++ b/source/extensions/filters/http/ratelimit/ratelimit.cc @@ -4,6 +4,7 @@ #include #include "envoy/http/codes.h" +#include "envoy/stream_info/stream_info.h" #include "source/common/common/assert.h" #include "source/common/common/enum_to_int.h" @@ -11,6 +12,7 @@ #include "source/common/http/codes.h" #include "source/common/http/header_utility.h" #include "source/common/router/config_impl.h" +#include "source/common/stream_info/uint32_accessor_impl.h" #include "source/extensions/filters/http/ratelimit/ratelimit_headers.h" namespace Envoy { @@ -18,6 +20,26 @@ namespace Extensions { namespace HttpFilters { namespace RateLimitFilter { +namespace { +constexpr absl::string_view HitsAddendFilterStateKey = "envoy.ratelimit.hits_addend"; + +class HitsAddendObjectFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return std::string(HitsAddendFilterStateKey); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + uint32_t hits_addend = 0; + if (absl::SimpleAtoi(data, &hits_addend)) { + return std::make_unique(hits_addend); + } + return nullptr; + } +}; + +REGISTER_FACTORY(HitsAddendObjectFactory, StreamInfo::FilterState::ObjectFactory); + +} // namespace + struct RcDetailsValues { // This request went above the configured limits for the rate limit filter. const std::string RateLimited = "request_rate_limited"; @@ -64,11 +86,19 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) { break; } + const StreamInfo::UInt32Accessor* hits_addend_filter_state = + callbacks_->streamInfo().filterState()->getDataReadOnly( + HitsAddendFilterStateKey); + double hits_addend = 0; + if (hits_addend_filter_state != nullptr) { + hits_addend = hits_addend_filter_state->value(); + } + if (!descriptors.empty()) { state_ = State::Calling; initiating_call_ = true; client_->limit(*this, getDomain(), descriptors, callbacks_->activeSpan(), - callbacks_->streamInfo(), 0); + callbacks_->streamInfo(), hits_addend); initiating_call_ = false; } } diff --git a/source/extensions/filters/http/rbac/rbac_filter.cc b/source/extensions/filters/http/rbac/rbac_filter.cc index e5ad66b2c9b9..e55924cfc861 100644 --- a/source/extensions/filters/http/rbac/rbac_filter.cc +++ b/source/extensions/filters/http/rbac/rbac_filter.cc @@ -1,3 +1,4 @@ +#include "rbac_filter.h" #include "source/extensions/filters/http/rbac/rbac_filter.h" #include "envoy/stats/scope.h" @@ -47,6 +48,9 @@ absl::Status ActionValidationVisitor::performDataInputValidation( {TypeUtil::descriptorFullNameToTypeUrl( envoy::extensions::matching::common_inputs::ssl::v3::SubjectInput::descriptor() ->full_name())}, + {TypeUtil::descriptorFullNameToTypeUrl(envoy::extensions::matching::common_inputs::network:: + v3::DynamicMetadataInput::descriptor() + ->full_name())}, {TypeUtil::descriptorFullNameToTypeUrl( xds::type::matcher::v3::HttpAttributesCelMatchInput::descriptor()->full_name())}}; if (allowed_inputs_set.contains(type_url)) { @@ -71,6 +75,29 @@ RoleBasedAccessControlFilterConfig::RoleBasedAccessControlFilterConfig( shadow_engine_(Filters::Common::RBAC::createShadowEngine( proto_config, context, validation_visitor, action_validation_visitor_)) {} +#define DEFINE_DYNAMIC_METADATA_STAT_KEY_GETTER(GETTER_NAME, PREFIX, ROUTE_LOCAL_PREFIX_OVERRIDE, \ + DYNAMIC_METADATA_KEY) \ + std::string RoleBasedAccessControlFilterConfig::GETTER_NAME( \ + const Http::StreamFilterCallbacks* callbacks) const { \ + const auto* route_local = Http::Utility::resolveMostSpecificPerFilterConfig< \ + RoleBasedAccessControlRouteSpecificFilterConfig>(callbacks); \ + std::string prefix = PREFIX; \ + if (route_local && !route_local->ROUTE_LOCAL_PREFIX_OVERRIDE().empty()) { \ + prefix = route_local->ROUTE_LOCAL_PREFIX_OVERRIDE(); \ + } \ + return prefix + \ + Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().DYNAMIC_METADATA_KEY; \ + } + +DEFINE_DYNAMIC_METADATA_STAT_KEY_GETTER(shadowEffectivePolicyIdField, shadow_rules_stat_prefix_, + shadowRulesStatPrefix, ShadowEffectivePolicyIdField) +DEFINE_DYNAMIC_METADATA_STAT_KEY_GETTER(shadowEngineResultField, shadow_rules_stat_prefix_, + shadowRulesStatPrefix, ShadowEngineResultField) +DEFINE_DYNAMIC_METADATA_STAT_KEY_GETTER(enforcedEffectivePolicyIdField, rules_stat_prefix_, + rulesStatPrefix, EnforcedEffectivePolicyIdField) +DEFINE_DYNAMIC_METADATA_STAT_KEY_GETTER(enforcedEngineResultField, rules_stat_prefix_, + rulesStatPrefix, EnforcedEngineResultField) + const Filters::Common::RBAC::RoleBasedAccessControlEngine* RoleBasedAccessControlFilterConfig::engine(const Http::StreamFilterCallbacks* callbacks, Filters::Common::RBAC::EnforcementMode mode) const { @@ -100,7 +127,9 @@ RoleBasedAccessControlRouteSpecificFilterConfig::RoleBasedAccessControlRouteSpec const envoy::extensions::filters::http::rbac::v3::RBACPerRoute& per_route_config, Server::Configuration::ServerFactoryContext& context, ProtobufMessage::ValidationVisitor& validation_visitor) - : per_rule_stats_(per_route_config.rbac().track_per_rule_stats()) { + : rules_stat_prefix_(per_route_config.rbac().rules_stat_prefix()), + shadow_rules_stat_prefix_(per_route_config.rbac().shadow_rules_stat_prefix()), + per_rule_stats_(per_route_config.rbac().track_per_rule_stats()) { // Moved from member initializer to ctor body to overcome clang false warning about memory // leak (clang-analyzer-cplusplus.NewDeleteLeaks,-warnings-as-errors). // Potentially https://lists.llvm.org/pipermail/llvm-bugs/2018-July/066769.html @@ -162,10 +191,11 @@ RoleBasedAccessControlFilter::decodeHeaders(Http::RequestHeaderMap& headers, boo } if (!effective_policy_id.empty()) { - *fields[config_->shadowEffectivePolicyIdField()].mutable_string_value() = effective_policy_id; + *fields[config_->shadowEffectivePolicyIdField(callbacks_)].mutable_string_value() = + effective_policy_id; } - *fields[config_->shadowEngineResultField()].mutable_string_value() = shadow_resp_code; + *fields[config_->shadowEngineResultField(callbacks_)].mutable_string_value() = shadow_resp_code; } const auto engine = config_->engine(callbacks_, Filters::Common::RBAC::EnforcementMode::Enforced); @@ -175,7 +205,7 @@ RoleBasedAccessControlFilter::decodeHeaders(Http::RequestHeaderMap& headers, boo callbacks_->streamInfo(), &effective_policy_id); const std::string log_policy_id = effective_policy_id.empty() ? "none" : effective_policy_id; if (!effective_policy_id.empty()) { - *fields[config_->enforcedEffectivePolicyIdField()].mutable_string_value() = + *fields[config_->enforcedEffectivePolicyIdField(callbacks_)].mutable_string_value() = effective_policy_id; } if (allowed) { @@ -185,7 +215,7 @@ RoleBasedAccessControlFilter::decodeHeaders(Http::RequestHeaderMap& headers, boo config_->stats().incPolicyAllowed(effective_policy_id); } - *fields[config_->enforcedEngineResultField()].mutable_string_value() = + *fields[config_->enforcedEngineResultField(callbacks_)].mutable_string_value() = Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().EngineResultAllowed; callbacks_->streamInfo().setDynamicMetadata("envoy.filters.http.rbac", metrics); @@ -200,7 +230,7 @@ RoleBasedAccessControlFilter::decodeHeaders(Http::RequestHeaderMap& headers, boo config_->stats().incPolicyDenied(effective_policy_id); } - *fields[config_->enforcedEngineResultField()].mutable_string_value() = + *fields[config_->enforcedEngineResultField(callbacks_)].mutable_string_value() = Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().EngineResultDenied; callbacks_->streamInfo().setDynamicMetadata("envoy.filters.http.rbac", metrics); diff --git a/source/extensions/filters/http/rbac/rbac_filter.h b/source/extensions/filters/http/rbac/rbac_filter.h index 9f021cb94e98..bb6748691fd2 100644 --- a/source/extensions/filters/http/rbac/rbac_filter.h +++ b/source/extensions/filters/http/rbac/rbac_filter.h @@ -35,10 +35,15 @@ class RoleBasedAccessControlRouteSpecificFilterConfig : public Router::RouteSpec return mode == Filters::Common::RBAC::EnforcementMode::Enforced ? engine_.get() : shadow_engine_.get(); } + std::string rulesStatPrefix() const { return rules_stat_prefix_; } + + std::string shadowRulesStatPrefix() const { return shadow_rules_stat_prefix_; } bool perRuleStatsEnabled() const { return per_rule_stats_; } private: + const std::string rules_stat_prefix_; + const std::string shadow_rules_stat_prefix_; ActionValidationVisitor action_validation_visitor_; std::unique_ptr engine_; std::unique_ptr shadow_engine_; @@ -57,23 +62,11 @@ class RoleBasedAccessControlFilterConfig { ProtobufMessage::ValidationVisitor& validation_visitor); Filters::Common::RBAC::RoleBasedAccessControlFilterStats& stats() { return stats_; } - std::string shadowEffectivePolicyIdField() const { - return shadow_rules_stat_prefix_ + - Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEffectivePolicyIdField; - } - std::string shadowEngineResultField() const { - return shadow_rules_stat_prefix_ + - Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEngineResultField; - } + std::string shadowEffectivePolicyIdField(const Http::StreamFilterCallbacks* callbacks) const; + std::string shadowEngineResultField(const Http::StreamFilterCallbacks* callbacks) const; - std::string enforcedEffectivePolicyIdField() const { - return rules_stat_prefix_ + Filters::Common::RBAC::DynamicMetadataKeysSingleton::get() - .EnforcedEffectivePolicyIdField; - } - std::string enforcedEngineResultField() const { - return rules_stat_prefix_ + - Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().EnforcedEngineResultField; - } + std::string enforcedEffectivePolicyIdField(const Http::StreamFilterCallbacks* callbacks) const; + std::string enforcedEngineResultField(const Http::StreamFilterCallbacks* callbacks) const; const Filters::Common::RBAC::RoleBasedAccessControlEngine* engine(const Http::StreamFilterCallbacks* callbacks, diff --git a/source/extensions/filters/http/thrift_to_metadata/filter.cc b/source/extensions/filters/http/thrift_to_metadata/filter.cc index 6c4c0e858825..23753568d326 100644 --- a/source/extensions/filters/http/thrift_to_metadata/filter.cc +++ b/source/extensions/filters/http/thrift_to_metadata/filter.cc @@ -182,19 +182,17 @@ Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_strea : Http::FilterDataStatus::StopIterationAndBuffer; } -Http::FilterTrailersStatus Filter::decodeTrailers(Http::RequestTrailerMap&) { +void Filter::decodeComplete() { if (!config_->shouldParseRequestMetadata() || request_processing_finished_) { - return Http::FilterTrailersStatus::Continue; + return; } ENVOY_LOG(trace, - "thrift to metadata filter decodeTrailers: handle incomplete request thrift message"); + "thrift to metadata filter decodeComplete: handle incomplete request thrift message"); // Handle incomplete request thrift message while we reach here. handleAllOnMissing(config_->requestRules(), *decoder_callbacks_, request_processing_finished_); config_->rqstats().invalid_thrift_body_.inc(); - - return Http::FilterTrailersStatus::Continue; } Http::FilterHeadersStatus Filter::encodeHeaders(Http::ResponseHeaderMap& headers, bool end_stream) { @@ -246,19 +244,17 @@ Http::FilterDataStatus Filter::encodeData(Buffer::Instance& data, bool end_strea : Http::FilterDataStatus::StopIterationAndBuffer; } -Http::FilterTrailersStatus Filter::encodeTrailers(Http::ResponseTrailerMap&) { +void Filter::encodeComplete() { if (!config_->shouldParseResponseMetadata() || response_processing_finished_) { - return Http::FilterTrailersStatus::Continue; + return; } ENVOY_LOG(trace, - "thrift to metadata filter encodeTrailers: handle incomplete response thrift message"); + "thrift to metadata filter encodeComplete: handle incomplete response thrift message"); // Handle incomplete response thrift message while we reach here. handleAllOnMissing(config_->responseRules(), *encoder_callbacks_, response_processing_finished_); config_->respstats().invalid_thrift_body_.inc(); - - return Http::FilterTrailersStatus::Continue; } bool Filter::processData(Buffer::Instance& incoming_data, Buffer::Instance& buffer, diff --git a/source/extensions/filters/http/thrift_to_metadata/filter.h b/source/extensions/filters/http/thrift_to_metadata/filter.h index 18d89b78621d..fe28ce3767c7 100644 --- a/source/extensions/filters/http/thrift_to_metadata/filter.h +++ b/source/extensions/filters/http/thrift_to_metadata/filter.h @@ -181,11 +181,11 @@ class Filter : public Http::PassThroughFilter, Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream) override; Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream) override; - Http::FilterTrailersStatus decodeTrailers(Http::RequestTrailerMap& trailers) override; + void decodeComplete() override; Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& headers, bool end_stream) override; Http::FilterDataStatus encodeData(Buffer::Instance& data, bool end_stream) override; - Http::FilterTrailersStatus encodeTrailers(Http::ResponseTrailerMap& trailers) override; + void encodeComplete() override; // PassThroughDecoderEventHandler FilterStatus messageBegin(MessageMetadataSharedPtr metadata) override; diff --git a/source/extensions/filters/network/common/redis/supported_commands.h b/source/extensions/filters/network/common/redis/supported_commands.h index 14a8a8686724..bbda434d72ab 100644 --- a/source/extensions/filters/network/common/redis/supported_commands.h +++ b/source/extensions/filters/network/common/redis/supported_commands.h @@ -28,9 +28,9 @@ struct SupportedCommands { "hincrbyfloat", "hkeys", "hlen", "hmget", "hmset", "hscan", "hset", "hsetnx", "hstrlen", "hvals", "incr", "incrby", "incrbyfloat", "lindex", "linsert", "llen", "lmove", "lpop", "lpush", "lpushx", "lrange", "lrem", "lset", "ltrim", "persist", "pexpire", "pexpireat", - "pfadd", "pfcount", "psetex", "pttl", "restore", "rpop", "rpush", "rpushx", "sadd", "scard", - "set", "setbit", "setex", "setnx", "setrange", "sismember", "smembers", "spop", - "srandmember", "srem", "sscan", "strlen", "ttl", "type", "watch", "xack", "xadd", + "pfadd", "pfcount", "psetex", "pttl", "publish", "restore", "rpop", "rpush", "rpushx", + "sadd", "scard", "set", "setbit", "setex", "setnx", "setrange", "sismember", "smembers", + "spop", "srandmember", "srem", "sscan", "strlen", "ttl", "type", "watch", "xack", "xadd", "xautoclaim", "xclaim", "xdel", "xlen", "xpending", "xrange", "xrevrange", "xtrim", "zadd", "zcard", "zcount", "zincrby", "zlexcount", "zpopmin", "zpopmax", "zrange", "zrangebylex", "zrangebyscore", "zrank", "zrem", "zremrangebylex", "zremrangebyrank", "zremrangebyscore", diff --git a/source/extensions/filters/network/generic_proxy/access_log.cc b/source/extensions/filters/network/generic_proxy/access_log.cc index ce635a84b410..a96df953494d 100644 --- a/source/extensions/filters/network/generic_proxy/access_log.cc +++ b/source/extensions/filters/network/generic_proxy/access_log.cc @@ -55,8 +55,8 @@ class SimpleCommandParser : public CommandParser { using ProviderFuncTable = absl::flat_hash_map; // CommandParser - FormatterProviderPtr parse(const std::string& command, const std::string& command_arg, - absl::optional& max_length) const override { + FormatterProviderPtr parse(absl::string_view command, absl::string_view command_arg, + absl::optional max_length) const override { const auto& provider_func_table = providerFuncTable(); const auto func_iter = provider_func_table.find(std::string(command)); if (func_iter == provider_func_table.end()) { diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index e538fbe89e72..a8a036a70a94 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -375,6 +375,7 @@ HttpConnectionManagerConfig::HttpConnectionManagerConfig( idle_timeout_(PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), idle_timeout)), max_connection_duration_( PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), max_connection_duration)), + http1_safe_max_connection_duration_(config.http1_safe_max_connection_duration()), max_stream_duration_( PROTOBUF_GET_OPTIONAL_MS(config.common_http_protocol_options(), max_stream_duration)), stream_idle_timeout_( @@ -782,7 +783,7 @@ bool HttpConnectionManagerConfig::createFilterChain(Http::FilterChainManager& ma bool HttpConnectionManagerConfig::createUpgradeFilterChain( absl::string_view upgrade_type, const Http::FilterChainFactory::UpgradeMap* per_route_upgrade_map, - Http::FilterChainManager& callbacks, const Http::FilterChainOptions& option) const { + Http::FilterChainManager& callbacks, const Http::FilterChainOptions& options) const { bool route_enabled = false; if (per_route_upgrade_map) { auto route_it = findUpgradeBoolCaseInsensitive(*per_route_upgrade_map, upgrade_type); @@ -807,7 +808,7 @@ bool HttpConnectionManagerConfig::createUpgradeFilterChain( filters_to_use = it->second.filter_factories.get(); } - Http::FilterChainUtility::createFilterChainForFactories(callbacks, option, *filters_to_use); + Http::FilterChainUtility::createFilterChainForFactories(callbacks, options, *filters_to_use); return true; } diff --git a/source/extensions/filters/network/http_connection_manager/config.h b/source/extensions/filters/network/http_connection_manager/config.h index 34dbfafcc2f9..566ff72bc996 100644 --- a/source/extensions/filters/network/http_connection_manager/config.h +++ b/source/extensions/filters/network/http_connection_manager/config.h @@ -44,7 +44,7 @@ namespace NetworkFilters { namespace HttpConnectionManager { using FilterConfigProviderManager = - Filter::FilterConfigProviderManager; /** @@ -149,7 +149,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, bool createUpgradeFilterChain(absl::string_view upgrade_type, const Http::FilterChainFactory::UpgradeMap* per_route_upgrade_map, Http::FilterChainManager& manager, - const Http::FilterChainOptions& option) const override; + const Http::FilterChainOptions& options) const override; // Http::ConnectionManagerConfig const Http::RequestIDExtensionSharedPtr& requestIDExtension() override { @@ -180,6 +180,9 @@ class HttpConnectionManagerConfig : Logger::Loggable, absl::optional maxConnectionDuration() const override { return max_connection_duration_; } + bool http1SafeMaxConnectionDuration() const override { + return http1_safe_max_connection_duration_; + } std::chrono::milliseconds streamIdleTimeout() const override { return stream_idle_timeout_; } std::chrono::milliseconds requestTimeout() const override { return request_timeout_; } std::chrono::milliseconds requestHeadersTimeout() const override { @@ -324,6 +327,7 @@ class HttpConnectionManagerConfig : Logger::Loggable, const uint32_t max_request_headers_count_; absl::optional idle_timeout_; absl::optional max_connection_duration_; + const bool http1_safe_max_connection_duration_; absl::optional max_stream_duration_; std::chrono::milliseconds stream_idle_timeout_; std::chrono::milliseconds request_timeout_; diff --git a/source/extensions/filters/network/rbac/rbac_filter.cc b/source/extensions/filters/network/rbac/rbac_filter.cc index 7d07de0f6d18..4e67a4ec4c81 100644 --- a/source/extensions/filters/network/rbac/rbac_filter.cc +++ b/source/extensions/filters/network/rbac/rbac_filter.cc @@ -63,9 +63,14 @@ RoleBasedAccessControlFilterConfig::RoleBasedAccessControlFilterConfig( action_validation_visitor_)), shadow_engine_(Filters::Common::RBAC::createShadowEngine( proto_config, context, validation_visitor, action_validation_visitor_)), - enforcement_type_(proto_config.enforcement_type()) {} + enforcement_type_(proto_config.enforcement_type()), + delay_deny_ms_(PROTOBUF_GET_MS_OR_DEFAULT(proto_config, delay_deny, 0)) {} Network::FilterStatus RoleBasedAccessControlFilter::onData(Buffer::Instance&, bool) { + if (is_delay_denied_) { + return Network::FilterStatus::StopIteration; + } + ENVOY_LOG( debug, "checking connection: requestedServerName: {}, sourceIP: {}, directRemoteIP: {}," @@ -118,7 +123,19 @@ Network::FilterStatus RoleBasedAccessControlFilter::onData(Buffer::Instance&, bo } else if (engine_result_ == Deny) { callbacks_->connection().streamInfo().setConnectionTerminationDetails( Filters::Common::RBAC::responseDetail(log_policy_id)); - callbacks_->connection().close(Network::ConnectionCloseType::NoFlush, "rbac_deny_close"); + + std::chrono::milliseconds duration = config_->delayDenyMs(); + if (duration > std::chrono::milliseconds(0)) { + ENVOY_LOG(debug, "connection will be delay denied in {}ms", duration.count()); + delay_timer_ = callbacks_->connection().dispatcher().createTimer( + [this]() -> void { closeConnection(); }); + ASSERT(!is_delay_denied_); + is_delay_denied_ = true; + callbacks_->connection().readDisable(true); + delay_timer_->enableTimer(duration); + } else { + closeConnection(); + } return Network::FilterStatus::StopIteration; } @@ -126,6 +143,24 @@ Network::FilterStatus RoleBasedAccessControlFilter::onData(Buffer::Instance&, bo return Network::FilterStatus::Continue; } +void RoleBasedAccessControlFilter::closeConnection() { + callbacks_->connection().close(Network::ConnectionCloseType::NoFlush, "rbac_deny_close"); +} + +void RoleBasedAccessControlFilter::resetTimerState() { + if (delay_timer_) { + delay_timer_->disableTimer(); + delay_timer_.reset(); + } +} + +void RoleBasedAccessControlFilter::onEvent(Network::ConnectionEvent event) { + if (event == Network::ConnectionEvent::RemoteClose || + event == Network::ConnectionEvent::LocalClose) { + resetTimerState(); + } +} + void RoleBasedAccessControlFilter::setDynamicMetadata(std::string shadow_engine_result, std::string shadow_policy_id) { ProtobufWkt::Struct metrics; diff --git a/source/extensions/filters/network/rbac/rbac_filter.h b/source/extensions/filters/network/rbac/rbac_filter.h index a534f7c88010..b68aea4a56d6 100644 --- a/source/extensions/filters/network/rbac/rbac_filter.h +++ b/source/extensions/filters/network/rbac/rbac_filter.h @@ -1,5 +1,6 @@ #pragma once +#include "envoy/event/timer.h" #include "envoy/extensions/filters/network/rbac/v3/rbac.pb.h" #include "envoy/network/connection.h" #include "envoy/network/filter.h" @@ -58,6 +59,8 @@ class RoleBasedAccessControlFilterConfig { return enforcement_type_; } + std::chrono::milliseconds delayDenyMs() const { return delay_deny_ms_; } + private: Filters::Common::RBAC::RoleBasedAccessControlFilterStats stats_; const std::string shadow_rules_stat_prefix_; @@ -66,6 +69,7 @@ class RoleBasedAccessControlFilterConfig { std::unique_ptr engine_; std::unique_ptr shadow_engine_; const envoy::extensions::filters::network::rbac::v3::RBAC::EnforcementType enforcement_type_; + std::chrono::milliseconds delay_deny_ms_; }; using RoleBasedAccessControlFilterConfigSharedPtr = @@ -75,6 +79,7 @@ using RoleBasedAccessControlFilterConfigSharedPtr = * Implementation of a basic RBAC network filter. */ class RoleBasedAccessControlFilter : public Network::ReadFilter, + public Network::ConnectionCallbacks, public Logger::Loggable { public: @@ -87,8 +92,14 @@ class RoleBasedAccessControlFilter : public Network::ReadFilter, Network::FilterStatus onNewConnection() override { return Network::FilterStatus::Continue; }; void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override { callbacks_ = &callbacks; + callbacks_->connection().addConnectionCallbacks(*this); } + // Network::ConnectionCallbacks + void onEvent(Network::ConnectionEvent event) override; + void onAboveWriteBufferHighWatermark() override {} + void onBelowWriteBufferLowWatermark() override {} + void setDynamicMetadata(std::string shadow_engine_result, std::string shadow_policy_id); private: @@ -98,6 +109,10 @@ class RoleBasedAccessControlFilter : public Network::ReadFilter, EngineResult shadow_engine_result_{Unknown}; Result checkEngine(Filters::Common::RBAC::EnforcementMode mode); + void closeConnection(); + void resetTimerState(); + Event::TimerPtr delay_timer_{nullptr}; + bool is_delay_denied_{false}; }; } // namespace RBACFilter diff --git a/source/extensions/filters/udp/udp_proxy/BUILD b/source/extensions/filters/udp/udp_proxy/BUILD index ba70f7ca39fe..dbc00fe8af00 100644 --- a/source/extensions/filters/udp/udp_proxy/BUILD +++ b/source/extensions/filters/udp/udp_proxy/BUILD @@ -48,8 +48,6 @@ envoy_cc_library( "//source/common/stream_info:stream_info_lib", "//source/common/upstream:load_balancer_context_base_lib", "//source/extensions/filters/udp/udp_proxy/router:router_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_config_interface", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "@envoy_api//envoy/config/accesslog/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/filters/udp/udp_proxy/v3:pkg_cc_proto", ], @@ -64,6 +62,7 @@ envoy_cc_extension( ":udp_proxy_filter_lib", "//envoy/registry", "//envoy/server:filter_config_interface", + "//source/common/filter:config_discovery_lib", "//source/common/formatter:substitution_format_string_lib", "@envoy_api//envoy/extensions/filters/udp/udp_proxy/v3:pkg_cc_proto", ], diff --git a/source/extensions/filters/udp/udp_proxy/config.cc b/source/extensions/filters/udp/udp_proxy/config.cc index 58dec2bb53a0..1fee7deedc54 100644 --- a/source/extensions/filters/udp/udp_proxy/config.cc +++ b/source/extensions/filters/udp/udp_proxy/config.cc @@ -145,10 +145,12 @@ UdpProxyFilterConfigImpl::UdpProxyFilterConfigImpl( MessageUtil::getJsonStringFromMessageOrError( static_cast(filter.typed_config()), true)); - auto& factory = Config::Utility::getAndCheckFactory(filter); + auto& factory = Config::Utility::getAndCheckFactory< + Server::Configuration::NamedUdpSessionFilterConfigFactory>(filter); ProtobufTypes::MessagePtr message = Envoy::Config::Utility::translateToFactoryConfig( filter, context.messageValidationVisitor(), factory); - FilterFactoryCb callback = factory.createFilterFactoryFromProto(*message, context); + Network::UdpSessionFilterFactoryCb callback = + factory.createFilterFactoryFromProto(*message, context); filter_factories_.push_back(callback); } } diff --git a/source/extensions/filters/udp/udp_proxy/config.h b/source/extensions/filters/udp/udp_proxy/config.h index 29793bf6d2a4..3ecc10711c6d 100644 --- a/source/extensions/filters/udp/udp_proxy/config.h +++ b/source/extensions/filters/udp/udp_proxy/config.h @@ -107,7 +107,7 @@ class TunnelingConfigImpl : public UdpTunnelingConfig { }; class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, - public FilterChainFactory, + public UdpSessionFilterChainFactory, Logger::Loggable { public: UdpProxyFilterConfigImpl( @@ -138,7 +138,7 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, const std::vector& proxyAccessLogs() const override { return proxy_access_logs_; } - const FilterChainFactory& sessionFilterFactory() const override { return *this; }; + const UdpSessionFilterChainFactory& sessionFilterFactory() const override { return *this; }; bool hasSessionFilters() const override { return !filter_factories_.empty(); } const UdpTunnelingConfigPtr& tunnelingConfig() const override { return tunneling_config_; }; bool flushAccessLogOnTunnelConnected() const override { @@ -149,9 +149,9 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, } Random::RandomGenerator& randomGenerator() const override { return random_generator_; } - // FilterChainFactory - void createFilterChain(FilterChainFactoryCallbacks& callbacks) const override { - for (const FilterFactoryCb& factory : filter_factories_) { + // UdpSessionFilterChainFactory + void createFilterChain(Network::UdpSessionFilterChainFactoryCallbacks& callbacks) const override { + for (const Network::UdpSessionFilterFactoryCb& factory : filter_factories_) { factory(callbacks); } }; @@ -178,7 +178,7 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, std::vector session_access_logs_; std::vector proxy_access_logs_; UdpTunnelingConfigPtr tunneling_config_; - std::list filter_factories_; + std::list filter_factories_; Random::RandomGenerator& random_generator_; }; diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/BUILD b/source/extensions/filters/udp/udp_proxy/session_filters/BUILD index 4cbdb01a5796..205b33895743 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/BUILD +++ b/source/extensions/filters/udp/udp_proxy/session_filters/BUILD @@ -8,42 +8,17 @@ licenses(["notice"]) # Apache 2 envoy_extension_package() -envoy_cc_library( - name = "filter_config_interface", - hdrs = ["filter_config.h"], - deps = [ - ":filter_interface", - "//envoy/config:typed_config_interface", - "//envoy/server:filter_config_interface", - "//source/common/common:macros", - "//source/common/protobuf:cc_wkt_protos", - ], -) - envoy_cc_library( name = "factory_base_lib", hdrs = ["factory_base.h"], visibility = ["//visibility:public"], deps = [ - ":filter_config_interface", + "//envoy/server:filter_config_interface", "//source/common/protobuf:utility_lib", ], ) -envoy_cc_library( - name = "filter_interface", - hdrs = ["filter.h"], - visibility = ["//visibility:public"], - deps = [ - "//envoy/network:listener_interface", - "//envoy/stream_info:stream_info_interface", - ], -) - envoy_cc_library( name = "pass_through_filter_lib", hdrs = ["pass_through_filter.h"], - deps = [ - ":filter_interface", - ], ) diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD index 2ddede80431e..79c4bfadb04c 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD +++ b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD @@ -19,7 +19,6 @@ envoy_cc_library( "//source/common/http:header_utility_lib", "//source/common/stream_info:uint32_accessor_lib", "//source/extensions/common/dynamic_forward_proxy:dns_cache_interface", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "@envoy_api//envoy/extensions/filters/udp/udp_proxy/session/dynamic_forward_proxy/v3:pkg_cc_proto", ], ) diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.cc b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.cc index 0a5062b4a2a0..e01357ba8c33 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.cc +++ b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.cc @@ -24,7 +24,7 @@ FilterFactoryCb DynamicForwardProxyNetworkFilterConfigFactory::createFilterFacto ProxyFilterConfigSharedPtr filter_config( std::make_shared(proto_config, cache_manager_factory, context)); - return [filter_config](FilterChainFactoryCallbacks& callbacks) -> void { + return [filter_config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addReadFilter(std::make_shared(filter_config)); }; } diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.h b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.h index 11d98c0eee97..ca2aad02f0ed 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/config.h @@ -14,6 +14,7 @@ namespace DynamicForwardProxy { using FilterConfig = envoy::extensions::filters::udp::udp_proxy::session::dynamic_forward_proxy::v3::FilterConfig; +using FilterFactoryCb = Network::UdpSessionFilterFactoryCb; /** * Config registration for the dynamic_forward_proxy filter. @see diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/proxy_filter.h b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/proxy_filter.h index 64516fb9ba5a..b9c4a26e687e 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/proxy_filter.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/proxy_filter.h @@ -7,7 +7,6 @@ #include "source/common/common/logger.h" #include "source/common/http/header_utility.h" #include "source/extensions/common/dynamic_forward_proxy/dns_cache.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" namespace Envoy { namespace Extensions { @@ -63,6 +62,10 @@ using ProxyFilterConfigSharedPtr = std::shared_ptr; using BufferedDatagramPtr = std::unique_ptr; using LoadDnsCacheEntryStatus = Common::DynamicForwardProxy::DnsCache::LoadDnsCacheEntryStatus; +using ReadFilter = Network::UdpSessionReadFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; + class ProxyFilter : public ReadFilter, public Extensions::Common::DynamicForwardProxy::DnsCache::LoadDnsCacheEntryCallbacks, diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h b/source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h index 9cbbc12d05bd..32d1bd457a7c 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h @@ -1,7 +1,8 @@ #pragma once +#include "envoy/server/filter_config.h" + #include "source/common/protobuf/utility.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter_config.h" namespace Envoy { namespace Extensions { @@ -9,6 +10,10 @@ namespace UdpFilters { namespace UdpProxy { namespace SessionFilters { +using FilterFactoryCb = Network::UdpSessionFilterFactoryCb; +using NamedUdpSessionFilterConfigFactory = + Server::Configuration::NamedUdpSessionFilterConfigFactory; + template class FactoryBase : public NamedUdpSessionFilterConfigFactory { public: FilterFactoryCb diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/filter.h b/source/extensions/filters/udp/udp_proxy/session_filters/filter.h deleted file mode 100644 index 8cedad217b15..000000000000 --- a/source/extensions/filters/udp/udp_proxy/session_filters/filter.h +++ /dev/null @@ -1,226 +0,0 @@ -#pragma once - -#include "envoy/buffer/buffer.h" -#include "envoy/network/listener.h" -#include "envoy/stream_info/stream_info.h" - -namespace Envoy { -namespace Extensions { -namespace UdpFilters { -namespace UdpProxy { -namespace SessionFilters { - -/** - * Common interface for ReadFilterCallbacks and WriteFilterCallbacks. - */ -class FilterCallbacks { -public: - virtual ~FilterCallbacks() = default; - - /** - * @return uint64_t the ID of the originating UDP session. - */ - virtual uint64_t sessionId() const PURE; - - /** - * @return StreamInfo for logging purposes. - */ - virtual StreamInfo::StreamInfo& streamInfo() PURE; - - /** - * Allows a filter to inject a datagram to successive filters in the session filter chain. - * The injected datagram will be iterated as a regular received datagram, and may also be - * stopped by further filters. This can be used, for example, to continue processing previously - * buffered datagrams by a filter after an asynchronous operation ended. - */ - virtual void injectDatagramToFilterChain(Network::UdpRecvData& data) PURE; -}; - -class ReadFilterCallbacks : public FilterCallbacks { -public: - ~ReadFilterCallbacks() override = default; - - /** - * If a read filter stopped filter iteration, continueFilterChain() can be called to continue the - * filter chain. It will have onNewSession() called if it was not previously called. - * @return false if the session is removed and no longer valid, otherwise returns true. - */ - virtual bool continueFilterChain() PURE; -}; - -class WriteFilterCallbacks : public FilterCallbacks {}; - -/** - * Return codes for read filter invocations. - */ -enum class ReadFilterStatus { - // Continue to further session filters. - Continue, - // Stop executing further session filters. - StopIteration, -}; - -class FilterBase { -public: - virtual ~FilterBase() = default; - - /** - * This routine is called before the access log handlers' final log() is called. Filters can use - * this callback to enrich the data passed in to the log handlers. - */ - void onSessionComplete() { - if (!on_session_complete_already_called_) { - onSessionCompleteInternal(); - on_session_complete_already_called_ = true; - } - } - -protected: - /** - * This routine is called by onSessionComplete to enrich the data passed in to the log handlers. - */ - virtual void onSessionCompleteInternal() { ASSERT(!on_session_complete_already_called_); } - -private: - bool on_session_complete_already_called_{false}; -}; - -/** - * Session read filter interface. - */ -class ReadFilter : public virtual FilterBase { -public: - ~ReadFilter() override = default; - - /** - * Called when a new UDP session is first established. Filters should do one time long term - * processing that needs to be done when a session is established. Filter chain iteration - * can be stopped if needed. - * @return status used by the filter manager to manage further filter iteration. - */ - virtual ReadFilterStatus onNewSession() PURE; - - /** - * Called when UDP datagram is read and matches the session that manages the filter. - * @param data supplies the read data which may be modified. - * @return status used by the filter manager to manage further filter iteration. - */ - virtual ReadFilterStatus onData(Network::UdpRecvData& data) PURE; - - /** - * Initializes the read filter callbacks used to interact with the filter manager. It will be - * called by the filter manager a single time when the filter is first registered. - * - * IMPORTANT: No outbound networking or complex processing should be done in this function. - * That should be done in the context of onNewSession() if needed. - * - * @param callbacks supplies the callbacks. - */ - virtual void initializeReadFilterCallbacks(ReadFilterCallbacks& callbacks) PURE; -}; - -using ReadFilterSharedPtr = std::shared_ptr; - -/** - * Return codes for write filter invocations. - */ -enum class WriteFilterStatus { - // Continue to further session filters. - Continue, - // Stop executing further session filters. - StopIteration, -}; - -/** - * Session write filter interface. - */ -class WriteFilter : public virtual FilterBase { -public: - ~WriteFilter() override = default; - - /** - * Called when data is to be written on the UDP session. - * @param data supplies the buffer to be written which may be modified. - * @return status used by the filter manager to manage further filter iteration. - */ - virtual WriteFilterStatus onWrite(Network::UdpRecvData& data) PURE; - - /** - * Initializes the write filter callbacks used to interact with the filter manager. It will be - * called by the filter manager a single time when the filter is first registered. - * - * IMPORTANT: No outbound networking or complex processing should be done in this function. - * That should be done in the context of ReadFilter::onNewSession() if needed. - * - * @param callbacks supplies the callbacks. - */ - virtual void initializeWriteFilterCallbacks(WriteFilterCallbacks& callbacks) PURE; -}; - -using WriteFilterSharedPtr = std::shared_ptr; - -/** - * A combination read and write filter. This allows a single filter instance to cover - * both the read and write paths. - */ -class Filter : public virtual ReadFilter, public virtual WriteFilter {}; -using FilterSharedPtr = std::shared_ptr; - -/** - * These callbacks are provided by the UDP session manager to the factory so that the factory - * can * build the filter chain in an application specific way. - */ -class FilterChainFactoryCallbacks { -public: - virtual ~FilterChainFactoryCallbacks() = default; - - /** - * Add a read filter that is used when reading UDP session data. - * @param filter supplies the filter to add. - */ - virtual void addReadFilter(ReadFilterSharedPtr filter) PURE; - - /** - * Add a write filter that is used when writing UDP session data. - * @param filter supplies the filter to add. - */ - virtual void addWriteFilter(WriteFilterSharedPtr filter) PURE; - - /** - * Add a bidirectional filter that is used when reading and writing UDP session data. - * @param filter supplies the filter to add. - */ - virtual void addFilter(FilterSharedPtr filter) PURE; -}; - -/** - * This function is used to wrap the creation of a UDP session filter chain for new sessions as they - * come in. Filter factories create the function at configuration initialization time, and then - * they are used at runtime. - * @param callbacks supplies the callbacks for the stream to install filters to. Typically the - * function will install a single filter, but it's technically possibly to install more than one - * if desired. - */ -using FilterFactoryCb = std::function; - -/** - * A FilterChainFactory is used by a UDP session manager to create a UDP session filter chain when - * a new session is created. - */ -class FilterChainFactory { -public: - virtual ~FilterChainFactory() = default; - - /** - * Called when a new UDP session is created. - * @param callbacks supplies the "sink" that is used for actually creating the filter chain. @see - * FilterChainFactoryCallbacks. - */ - virtual void createFilterChain(FilterChainFactoryCallbacks& callbacks) const PURE; -}; - -} // namespace SessionFilters -} // namespace UdpProxy -} // namespace UdpFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/filter_config.h b/source/extensions/filters/udp/udp_proxy/session_filters/filter_config.h deleted file mode 100644 index 07b41415b554..000000000000 --- a/source/extensions/filters/udp/udp_proxy/session_filters/filter_config.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "envoy/config/typed_config.h" -#include "envoy/server/filter_config.h" - -#include "source/common/common/macros.h" -#include "source/common/protobuf/protobuf.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" - -namespace Envoy { -namespace Extensions { -namespace UdpFilters { -namespace UdpProxy { -namespace SessionFilters { - -/** - * Implemented by each UDP session filter and registered via Registry::registerFactory or the - * convenience class RegisterFactory. - */ -class NamedUdpSessionFilterConfigFactory : public Envoy::Config::TypedFactory { -public: - ~NamedUdpSessionFilterConfigFactory() override = default; - - /** - * Create a particular UDP session filter factory implementation. If the implementation is - * unable to produce a factory with the provided parameters, it should throw an EnvoyException - * in the case of general error. The returned callback should always be initialized. - * @param config supplies the configuration for the filter - * @param context supplies the filter's context. - * @return FilterFactoryCb the factory creation function. - */ - virtual FilterFactoryCb - createFilterFactoryFromProto(const Protobuf::Message& config, - Server::Configuration::FactoryContext& context) PURE; - - std::string category() const override { return "envoy.filters.udp.session"; } -}; - -} // namespace SessionFilters -} // namespace UdpProxy -} // namespace UdpFilters -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/BUILD b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/BUILD index 264c6840f882..bc9302c3fff0 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/BUILD +++ b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/BUILD @@ -17,7 +17,6 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", "//source/common/common:assert_lib", "//source/common/common:hex_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "@com_github_google_quiche//:quiche_common_capsule_lib", "@com_github_google_quiche//:quiche_common_connect_udp_datagram_payload_lib", "@envoy_api//envoy/extensions/filters/udp/udp_proxy/session/http_capsule/v3:pkg_cc_proto", diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.cc b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.cc index 9623e87472b3..57e3bbbac64b 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.cc +++ b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.cc @@ -14,7 +14,7 @@ namespace HttpCapsule { FilterFactoryCb HttpCapsuleFilterConfigFactory::createFilterFactoryFromProtoTyped( const FilterConfig&, Server::Configuration::FactoryContext& context) { - return [&context](FilterChainFactoryCallbacks& callbacks) -> void { + return [&context](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addFilter( std::make_shared(context.serverFactoryContext().timeSource())); }; diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.h b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.h index 3ac7f37a5911..37f06e642327 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/config.h @@ -14,6 +14,7 @@ namespace HttpCapsule { using FilterConfig = envoy::extensions::filters::udp::udp_proxy::session::http_capsule::v3::FilterConfig; +using FilterFactoryCb = Network::UdpSessionFilterFactoryCb; /** * Config registration for the http_capsule filter. @see diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/http_capsule.h b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/http_capsule.h index 0b5dea6d60a6..f165fa60c66a 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/http_capsule.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/http_capsule/http_capsule.h @@ -1,9 +1,10 @@ #pragma once #include "envoy/extensions/filters/udp/udp_proxy/session/http_capsule/v3/http_capsule.pb.h" +#include "envoy/network/filter.h" +#include "envoy/network/listener.h" #include "source/common/common/logger.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" #include "quiche/common/capsule.h" #include "quiche/common/simple_buffer_allocator.h" @@ -15,6 +16,12 @@ namespace UdpProxy { namespace SessionFilters { namespace HttpCapsule { +using Filter = Network::UdpSessionFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using WriteFilterStatus = Network::UdpSessionWriteFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; +using WriteFilterCallbacks = Network::UdpSessionWriteFilterCallbacks; + class HttpCapsuleFilter : public Filter, public quiche::CapsuleParser::Visitor, Logger::Loggable { diff --git a/source/extensions/filters/udp/udp_proxy/session_filters/pass_through_filter.h b/source/extensions/filters/udp/udp_proxy/session_filters/pass_through_filter.h index 846667475a62..3fd2789ec504 100644 --- a/source/extensions/filters/udp/udp_proxy/session_filters/pass_through_filter.h +++ b/source/extensions/filters/udp/udp_proxy/session_filters/pass_through_filter.h @@ -1,6 +1,6 @@ #pragma once -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" +#include "envoy/network/filter.h" namespace Envoy { namespace Extensions { @@ -8,6 +8,14 @@ namespace UdpFilters { namespace UdpProxy { namespace SessionFilters { +using Filter = Network::UdpSessionFilter; +using ReadFilter = Network::UdpSessionReadFilter; +using WriteFilter = Network::UdpSessionWriteFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using WriteFilterStatus = Network::UdpSessionWriteFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; +using WriteFilterCallbacks = Network::UdpSessionWriteFilterCallbacks; + /** * Pass through UDP session read filter. Continue at each state within the series of * transitions, and pass through the read data. diff --git a/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h b/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h index 9ebcd93b5a45..245c3a40dc82 100644 --- a/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h +++ b/source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h @@ -31,8 +31,6 @@ #include "source/common/upstream/load_balancer_context_base.h" #include "source/extensions/filters/udp/udp_proxy/hash_policy_impl.h" #include "source/extensions/filters/udp/udp_proxy/router/router_impl.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter_config.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" @@ -42,8 +40,6 @@ namespace Extensions { namespace UdpFilters { namespace UdpProxy { -using namespace UdpProxy::SessionFilters; - /** * All UDP proxy downstream stats. @see stats_macros.h */ @@ -116,6 +112,8 @@ class UdpTunnelingConfig { using UdpTunnelingConfigPtr = std::unique_ptr; +using UdpSessionFilterChainFactory = Network::UdpSessionFilterChainFactory; + class UdpProxyFilterConfig { public: virtual ~UdpProxyFilterConfig() = default; @@ -133,7 +131,7 @@ class UdpProxyFilterConfig { virtual const Network::ResolvedUdpSocketConfig& upstreamSocketConfig() const PURE; virtual const std::vector& sessionAccessLogs() const PURE; virtual const std::vector& proxyAccessLogs() const PURE; - virtual const FilterChainFactory& sessionFilterFactory() const PURE; + virtual const UdpSessionFilterChainFactory& sessionFilterFactory() const PURE; virtual bool hasSessionFilters() const PURE; virtual const UdpTunnelingConfigPtr& tunnelingConfig() const PURE; virtual bool flushAccessLogOnTunnelConnected() const PURE; @@ -469,6 +467,15 @@ class TunnelingConnectionPoolFactory { using TunnelingConnectionPoolFactoryPtr = std::unique_ptr; +using FilterSharedPtr = Network::UdpSessionFilterSharedPtr; +using ReadFilterSharedPtr = Network::UdpSessionReadFilterSharedPtr; +using WriteFilterSharedPtr = Network::UdpSessionWriteFilterSharedPtr; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; +using WriteFilterCallbacks = Network::UdpSessionWriteFilterCallbacks; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using WriteFilterStatus = Network::UdpSessionWriteFilterStatus; +using FilterChainFactoryCallbacks = Network::UdpSessionFilterChainFactoryCallbacks; + class UdpProxyFilter : public Network::UdpListenerReadFilter, public Upstream::ClusterUpdateCallbacks, Logger::Loggable { diff --git a/source/extensions/formatter/cel/cel.cc b/source/extensions/formatter/cel/cel.cc index ffee3e8c73ff..dffd22063470 100644 --- a/source/extensions/formatter/cel/cel.cc +++ b/source/extensions/formatter/cel/cel.cc @@ -53,8 +53,8 @@ CELFormatter::formatValueWithContext(const Envoy::Formatter::HttpFormatterContex } ::Envoy::Formatter::FormatterProviderPtr -CELFormatterCommandParser::parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const { +CELFormatterCommandParser::parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const { #if defined(USE_CEL_PARSER) if (command == "CEL") { auto parse_status = google::api::expr::parser::Parse(subcommand); diff --git a/source/extensions/formatter/cel/cel.h b/source/extensions/formatter/cel/cel.h index 2c5a600a3397..c7ad51af7e68 100644 --- a/source/extensions/formatter/cel/cel.h +++ b/source/extensions/formatter/cel/cel.h @@ -37,9 +37,9 @@ class CELFormatterCommandParser : public ::Envoy::Formatter::CommandParser { CELFormatterCommandParser(Server::Configuration::CommonFactoryContext& context) : local_info_(context.localInfo()), expr_builder_(Extensions::Filters::Common::Expr::getBuilder(context)){}; - ::Envoy::Formatter::FormatterProviderPtr parse(const std::string& command, - const std::string& subcommand, - absl::optional& max_length) const override; + ::Envoy::Formatter::FormatterProviderPtr parse(absl::string_view command, + absl::string_view subcommand, + absl::optional max_length) const override; private: const ::Envoy::LocalInfo::LocalInfo& local_info_; diff --git a/source/extensions/formatter/metadata/metadata.cc b/source/extensions/formatter/metadata/metadata.cc index 1046dc95d4a0..6dfc147eac86 100644 --- a/source/extensions/formatter/metadata/metadata.cc +++ b/source/extensions/formatter/metadata/metadata.cc @@ -16,13 +16,13 @@ namespace Formatter { // Metadata formatter for route's metadata. class RouteMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter { public: - RouteMetadataFormatter(const std::string& filter_namespace, const std::vector& path, + RouteMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length) : ::Envoy::Formatter::MetadataFormatter(filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) -> const envoy::config::core::v3::Metadata* { auto route = stream_info.route(); - if (route == nullptr) { return nullptr; } @@ -33,8 +33,9 @@ class RouteMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter { // Metadata formatter for listener metadata. class ListenerMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter { public: - ListenerMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, absl::optional max_length) + ListenerMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, + absl::optional max_length) : ::Envoy::Formatter::MetadataFormatter( filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) @@ -50,8 +51,8 @@ class ListenerMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter { // Metadata formatter for virtual host metadata. class VirtualHostMetadataFormatter : public ::Envoy::Formatter::MetadataFormatter { public: - VirtualHostMetadataFormatter(const std::string& filter_namespace, - const std::vector& path, + VirtualHostMetadataFormatter(absl::string_view filter_namespace, + const std::vector& path, absl::optional max_length) : ::Envoy::Formatter::MetadataFormatter(filter_namespace, path, max_length, [](const StreamInfo::StreamInfo& stream_info) @@ -65,59 +66,68 @@ class VirtualHostMetadataFormatter : public ::Envoy::Formatter::MetadataFormatte }) {} }; -// Constructor registers all types of supported metadata along with the -// handlers accessing the required metadata type. -MetadataFormatterCommandParser::MetadataFormatterCommandParser() { - metadata_formatter_providers_["DYNAMIC"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique<::Envoy::Formatter::DynamicMetadataFormatter>(filter_namespace, path, - max_length); - }; - metadata_formatter_providers_["CLUSTER"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique<::Envoy::Formatter::ClusterMetadataFormatter>(filter_namespace, path, - max_length); - }; - metadata_formatter_providers_["ROUTE"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique(filter_namespace, path, max_length); - }; - metadata_formatter_providers_["UPSTREAM_HOST"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique<::Envoy::Formatter::UpstreamHostMetadataFormatter>(filter_namespace, - path, max_length); - }; +// Map used to dispatch types of metadata to individual handlers which will +// access required metadata object. +using FormatterProviderFunc = std::function<::Envoy::Formatter::StreamInfoFormatterProviderPtr( + absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length)>; - metadata_formatter_providers_["LISTENER"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique(filter_namespace, path, max_length); - }; +using FormatterProviderFuncTable = absl::flat_hash_map; - metadata_formatter_providers_["VIRTUAL_HOST"] = [](const std::string& filter_namespace, - const std::vector& path, - absl::optional max_length) { - return std::make_unique(filter_namespace, path, max_length); - }; +const auto& formatterProviderFuncTable() { + CONSTRUCT_ON_FIRST_USE( + FormatterProviderFuncTable, + { + {"DYNAMIC", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique<::Envoy::Formatter::DynamicMetadataFormatter>( + filter_namespace, path, max_length); + }}, + {"CLUSTER", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique<::Envoy::Formatter::ClusterMetadataFormatter>( + filter_namespace, path, max_length); + }}, + {"ROUTE", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique(filter_namespace, path, max_length); + }}, + {"UPSTREAM_HOST", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique<::Envoy::Formatter::UpstreamHostMetadataFormatter>( + filter_namespace, path, max_length); + }}, + {"LISTENER", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique(filter_namespace, path, max_length); + }}, + {"VIRTUAL_HOST", + [](absl::string_view filter_namespace, const std::vector& path, + absl::optional max_length) { + return std::make_unique(filter_namespace, path, + max_length); + }}, + }); } ::Envoy::Formatter::FormatterProviderPtr -MetadataFormatterCommandParser::parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const { +MetadataFormatterCommandParser::parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const { if (command == "METADATA") { // Extract type of metadata and keys. - std::string type, filter_namespace; - std::vector path; + absl::string_view type, filter_namespace; + std::vector path; ::Envoy::Formatter::SubstitutionFormatUtils::parseSubcommand(subcommand, ':', type, filter_namespace, path); - auto provider = metadata_formatter_providers_.find(type); - if (provider == metadata_formatter_providers_.end()) { + auto provider = formatterProviderFuncTable().find(type); + if (provider == formatterProviderFuncTable().end()) { throw EnvoyException(absl::StrCat(type, " is not supported type of metadata")); } diff --git a/source/extensions/formatter/metadata/metadata.h b/source/extensions/formatter/metadata/metadata.h index b6c9a02066fd..c4e8e287b863 100644 --- a/source/extensions/formatter/metadata/metadata.h +++ b/source/extensions/formatter/metadata/metadata.h @@ -15,18 +15,10 @@ namespace Formatter { // Access log handler for METADATA() command. class MetadataFormatterCommandParser : public ::Envoy::Formatter::CommandParser { public: - MetadataFormatterCommandParser(); - ::Envoy::Formatter::FormatterProviderPtr parse(const std::string& command, - const std::string& subcommand, - absl::optional& max_length) const override; - -private: - // Map used to dispatch types of metadata to individual handlers which will - // access required metadata object. - using FormatterProviderFunc = std::function<::Envoy::Formatter::StreamInfoFormatterProviderPtr( - const std::string& filter_namespace, const std::vector& path, - absl::optional max_length)>; - std::map metadata_formatter_providers_; + MetadataFormatterCommandParser() = default; + ::Envoy::Formatter::FormatterProviderPtr parse(absl::string_view command, + absl::string_view subcommand, + absl::optional max_length) const override; }; } // namespace Formatter diff --git a/source/extensions/formatter/req_without_query/req_without_query.cc b/source/extensions/formatter/req_without_query/req_without_query.cc index 4bcf9025f63c..cf5e07eaac60 100644 --- a/source/extensions/formatter/req_without_query/req_without_query.cc +++ b/source/extensions/formatter/req_without_query/req_without_query.cc @@ -21,8 +21,8 @@ void truncate(std::string& str, absl::optional max_length) { } // namespace -ReqWithoutQuery::ReqWithoutQuery(const std::string& main_header, - const std::string& alternative_header, +ReqWithoutQuery::ReqWithoutQuery(absl::string_view main_header, + absl::string_view alternative_header, absl::optional max_length) : main_header_(main_header), alternative_header_(alternative_header), max_length_(max_length) {} @@ -66,16 +66,14 @@ const Http::HeaderEntry* ReqWithoutQuery::findHeader(const Http::HeaderMap& head } ::Envoy::Formatter::FormatterProviderPtr -ReqWithoutQueryCommandParser::parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const { +ReqWithoutQueryCommandParser::parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const { if (command == "REQ_WITHOUT_QUERY") { - std::string main_header, alternative_header; - - THROW_IF_NOT_OK(Envoy::Formatter::SubstitutionFormatUtils::parseSubcommandHeaders( - subcommand, main_header, alternative_header)); - return std::make_unique(main_header, alternative_header, max_length); + auto status_or = Envoy::Formatter::SubstitutionFormatUtils::parseSubcommandHeaders(subcommand); + THROW_IF_NOT_OK_REF(status_or.status()); + return std::make_unique(status_or.value().first, status_or.value().second, + max_length); } - return nullptr; } diff --git a/source/extensions/formatter/req_without_query/req_without_query.h b/source/extensions/formatter/req_without_query/req_without_query.h index b2d16922ef61..a4c1be0df82e 100644 --- a/source/extensions/formatter/req_without_query/req_without_query.h +++ b/source/extensions/formatter/req_without_query/req_without_query.h @@ -14,7 +14,7 @@ namespace Formatter { class ReqWithoutQuery : public ::Envoy::Formatter::FormatterProvider { public: - ReqWithoutQuery(const std::string& main_header, const std::string& alternative_header, + ReqWithoutQuery(absl::string_view main_header, absl::string_view alternative_header, absl::optional max_length); absl::optional @@ -26,17 +26,17 @@ class ReqWithoutQuery : public ::Envoy::Formatter::FormatterProvider { private: const Http::HeaderEntry* findHeader(const Http::HeaderMap& headers) const; - Http::LowerCaseString main_header_; - Http::LowerCaseString alternative_header_; - absl::optional max_length_; + const Http::LowerCaseString main_header_; + const Http::LowerCaseString alternative_header_; + const absl::optional max_length_; }; class ReqWithoutQueryCommandParser : public ::Envoy::Formatter::CommandParser { public: ReqWithoutQueryCommandParser() = default; - ::Envoy::Formatter::FormatterProviderPtr parse(const std::string& command, - const std::string& subcommand, - absl::optional& max_length) const override; + ::Envoy::Formatter::FormatterProviderPtr parse(absl::string_view command, + absl::string_view subcommand, + absl::optional max_length) const override; }; } // namespace Formatter diff --git a/source/extensions/load_balancing_policies/cluster_provided/config.h b/source/extensions/load_balancing_policies/cluster_provided/config.h index 3bad53202292..cc624f11fabe 100644 --- a/source/extensions/load_balancing_policies/cluster_provided/config.h +++ b/source/extensions/load_balancing_policies/cluster_provided/config.h @@ -30,7 +30,8 @@ class Factory Random::RandomGenerator& random, TimeSource& time_source) override; - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message&, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message&, ProtobufMessage::ValidationVisitor&) override { return std::make_unique(); } diff --git a/source/extensions/load_balancing_policies/least_request/config.h b/source/extensions/load_balancing_policies/least_request/config.h index 3d3f92372de9..746f99ab5bf4 100644 --- a/source/extensions/load_balancing_policies/least_request/config.h +++ b/source/extensions/load_balancing_policies/least_request/config.h @@ -58,9 +58,9 @@ class Factory : public Common::FactoryBase::get(&config); ASSERT(active_or_legacy.hasLegacy() || active_or_legacy.hasActive()); diff --git a/source/extensions/load_balancing_policies/maglev/config.h b/source/extensions/load_balancing_policies/maglev/config.h index 294e370c850b..486cdd319a06 100644 --- a/source/extensions/load_balancing_policies/maglev/config.h +++ b/source/extensions/load_balancing_policies/maglev/config.h @@ -28,7 +28,8 @@ class Factory : public Upstream::TypedLoadBalancerFactoryBase { Random::RandomGenerator& random, TimeSource& time_source) override; - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor&) override { auto active_or_legacy = Common::ActiveOrLegacy::get(&config); diff --git a/source/extensions/load_balancing_policies/random/config.h b/source/extensions/load_balancing_policies/random/config.h index 25a3991f65e0..a65e6afee7a4 100644 --- a/source/extensions/load_balancing_policies/random/config.h +++ b/source/extensions/load_balancing_policies/random/config.h @@ -43,7 +43,8 @@ class Factory : public Common::FactoryBase { public: Factory() : FactoryBase("envoy.load_balancing_policies.random") {} - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor&) override { auto typed_config = dynamic_cast(&config); if (typed_config == nullptr) { diff --git a/source/extensions/load_balancing_policies/ring_hash/config.h b/source/extensions/load_balancing_policies/ring_hash/config.h index 16af59ff05b1..636540a873e3 100644 --- a/source/extensions/load_balancing_policies/ring_hash/config.h +++ b/source/extensions/load_balancing_policies/ring_hash/config.h @@ -28,7 +28,8 @@ class Factory : public Upstream::TypedLoadBalancerFactoryBase { Random::RandomGenerator& random, TimeSource& time_source) override; - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor&) override { auto active_or_legacy = Common::ActiveOrLegacy::get(&config); diff --git a/source/extensions/load_balancing_policies/round_robin/config.h b/source/extensions/load_balancing_policies/round_robin/config.h index c2ad4dca934b..bf78fdbe2a36 100644 --- a/source/extensions/load_balancing_policies/round_robin/config.h +++ b/source/extensions/load_balancing_policies/round_robin/config.h @@ -57,9 +57,9 @@ class Factory : public Common::FactoryBase public: Factory() : FactoryBase("envoy.load_balancing_policies.round_robin") {} - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor&) override { - auto active_or_legacy = Common::ActiveOrLegacy::get(&config); ASSERT(active_or_legacy.hasLegacy() || active_or_legacy.hasActive()); diff --git a/source/extensions/load_balancing_policies/subset/config.cc b/source/extensions/load_balancing_policies/subset/config.cc index 05eb9588361a..a788b26061dd 100644 --- a/source/extensions/load_balancing_policies/subset/config.cc +++ b/source/extensions/load_balancing_policies/subset/config.cc @@ -71,7 +71,8 @@ SubsetLbFactory::create(OptRef lb_config, } Upstream::LoadBalancerConfigPtr -SubsetLbFactory::loadConfig(const Protobuf::Message& config, +SubsetLbFactory::loadConfig(Upstream::LoadBalancerFactoryContext& lb_factory_context, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor& visitor) { auto active_or_legacy = Common::ActiveOrLegacy::get(&config); ASSERT(active_or_legacy.hasLegacy() || active_or_legacy.hasActive()); @@ -84,13 +85,14 @@ SubsetLbFactory::loadConfig(const Protobuf::Message& config, envoy::config::cluster::v3::Cluster::LbPolicy_Name( active_or_legacy.legacy()->lb_policy()))); } - return std::make_unique(*active_or_legacy.legacy(), - visitor); + return std::make_unique( + lb_factory_context, *active_or_legacy.legacy(), visitor); } // Load the subset load balancer configuration. This will contains child load balancer // config and child load balancer factory. - return std::make_unique(*active_or_legacy.active(), visitor); + return std::make_unique(lb_factory_context, + *active_or_legacy.active(), visitor); } /** diff --git a/source/extensions/load_balancing_policies/subset/config.h b/source/extensions/load_balancing_policies/subset/config.h index 0c49d8862bfb..80addf2150fb 100644 --- a/source/extensions/load_balancing_policies/subset/config.h +++ b/source/extensions/load_balancing_policies/subset/config.h @@ -24,8 +24,9 @@ class SubsetLbFactory Random::RandomGenerator& random, TimeSource& time_source) override; - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message& config, - ProtobufMessage::ValidationVisitor& visitor) override; + Upstream::LoadBalancerConfigPtr + loadConfig(Upstream::LoadBalancerFactoryContext& lb_factory_context, + const Protobuf::Message& config, ProtobufMessage::ValidationVisitor& visitor) override; }; } // namespace Subset diff --git a/source/extensions/load_balancing_policies/subset/subset_lb_config.cc b/source/extensions/load_balancing_policies/subset/subset_lb_config.cc index 2c0994306f69..500022395c0f 100644 --- a/source/extensions/load_balancing_policies/subset/subset_lb_config.cc +++ b/source/extensions/load_balancing_policies/subset/subset_lb_config.cc @@ -48,10 +48,10 @@ SubsetSelector::SubsetSelector(const Protobuf::RepeatedPtrField& se } } -SubsetLoadBalancerConfig::SubsetLoadBalancerConfig(const SubsetLbConfigProto& subset_config, - ProtobufMessage::ValidationVisitor& visitor) +SubsetLoadBalancerConfig::SubsetLoadBalancerConfig( + Upstream::LoadBalancerFactoryContext& lb_factory_context, + const SubsetLbConfigProto& subset_config, ProtobufMessage::ValidationVisitor& visitor) : subset_info_(std::make_unique(subset_config)) { - absl::InlinedVector missing_policies; for (const auto& policy : subset_config.subset_lb_policy().policies()) { @@ -64,7 +64,7 @@ SubsetLoadBalancerConfig::SubsetLoadBalancerConfig(const SubsetLbConfigProto& su Config::Utility::translateOpaqueConfig(policy.typed_extension_config().typed_config(), visitor, *sub_lb_proto_message); - child_lb_config_ = factory->loadConfig(*sub_lb_proto_message, visitor); + child_lb_config_ = factory->loadConfig(lb_factory_context, *sub_lb_proto_message, visitor); child_lb_factory_ = factory; break; } @@ -79,13 +79,14 @@ SubsetLoadBalancerConfig::SubsetLoadBalancerConfig(const SubsetLbConfigProto& su } } -SubsetLoadBalancerConfig::SubsetLoadBalancerConfig(const ClusterProto& cluster, - ProtobufMessage::ValidationVisitor& visitor) +SubsetLoadBalancerConfig::SubsetLoadBalancerConfig( + Upstream::LoadBalancerFactoryContext& lb_factory_context, const ClusterProto& cluster, + ProtobufMessage::ValidationVisitor& visitor) : subset_info_(std::make_unique(cluster.lb_subset_config())) { ASSERT(subset_info_->isEnabled()); - auto sub_lb_pair = - LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProtoWithoutSubset(cluster, visitor); + auto sub_lb_pair = LegacyLbPolicyConfigHelper::getTypedLbConfigFromLegacyProtoWithoutSubset( + lb_factory_context, cluster, visitor); if (!sub_lb_pair.ok()) { throw EnvoyException(std::string(sub_lb_pair.status().message())); } diff --git a/source/extensions/load_balancing_policies/subset/subset_lb_config.h b/source/extensions/load_balancing_policies/subset/subset_lb_config.h index 6199d31a6f1b..86b1deaff036 100644 --- a/source/extensions/load_balancing_policies/subset/subset_lb_config.h +++ b/source/extensions/load_balancing_policies/subset/subset_lb_config.h @@ -209,9 +209,11 @@ using DefaultLoadBalancerSubsetInfo = ConstSingleton class SubsetLoadBalancerConfig : public Upstream::LoadBalancerConfig { public: - SubsetLoadBalancerConfig(const SubsetLbConfigProto& subset_config, + SubsetLoadBalancerConfig(Upstream::LoadBalancerFactoryContext& lb_factory_context, + const SubsetLbConfigProto& subset_config, ProtobufMessage::ValidationVisitor& visitor); - SubsetLoadBalancerConfig(const ClusterProto& cluster, + SubsetLoadBalancerConfig(Upstream::LoadBalancerFactoryContext& lb_factory_context, + const ClusterProto& cluster, ProtobufMessage::ValidationVisitor& visitor); SubsetLoadBalancerConfig(LoadBalancerSubsetInfoPtr subset_info, TypedLoadBalancerFactory* child_factory, diff --git a/source/extensions/matching/http/metadata_input/BUILD b/source/extensions/matching/http/metadata_input/BUILD new file mode 100644 index 000000000000..8415d265c488 --- /dev/null +++ b/source/extensions/matching/http/metadata_input/BUILD @@ -0,0 +1,22 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "metadata_input_lib", + srcs = ["meta_input.cc"], + hdrs = ["meta_input.h"], + deps = [ + "//envoy/http:filter_interface", + "//envoy/matcher:matcher_interface", + "//envoy/registry", + "//source/common/config:metadata_lib", + "@envoy_api//envoy/extensions/matching/common_inputs/network/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/matching/http/metadata_input/meta_input.cc b/source/extensions/matching/http/metadata_input/meta_input.cc new file mode 100644 index 000000000000..f5542211b4b7 --- /dev/null +++ b/source/extensions/matching/http/metadata_input/meta_input.cc @@ -0,0 +1,20 @@ +#include "source/extensions/matching/http/metadata_input/meta_input.h" + +#include "envoy/registry/registry.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace Http { +namespace MetadataInput { + +class HttpDynamicMetadataInputFactory + : public DynamicMetadataInputBaseFactory {}; +REGISTER_FACTORY(HttpDynamicMetadataInputFactory, + Matcher::DataInputFactory); + +} // namespace MetadataInput +} // namespace Http +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/http/metadata_input/meta_input.h b/source/extensions/matching/http/metadata_input/meta_input.h new file mode 100644 index 000000000000..cec7b0253052 --- /dev/null +++ b/source/extensions/matching/http/metadata_input/meta_input.h @@ -0,0 +1,82 @@ +#pragma once + +#include "envoy/extensions/matching/common_inputs/network/v3/network_inputs.pb.h" +#include "envoy/extensions/matching/common_inputs/network/v3/network_inputs.pb.validate.h" +#include "envoy/http/filter.h" +#include "envoy/matcher/matcher.h" + +#include "source/common/config/metadata.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace Http { +namespace MetadataInput { + +class MetadataMatchData : public ::Envoy::Matcher::CustomMatchData { +public: + explicit MetadataMatchData(const ProtobufWkt::Value& value) : value_(value) {} + const ProtobufWkt::Value& value_; +}; + +template +class DynamicMetadataInput : public Matcher::DataInput { +public: + DynamicMetadataInput( + const envoy::extensions::matching::common_inputs::network::v3::DynamicMetadataInput& + input_config) + : filter_(input_config.filter()), path_(initializePath(input_config.path())) {} + + Matcher::DataInputGetResult get(const MatchingDataType& data) const override { + return {Matcher::DataInputGetResult::DataAvailability::AllDataAvailable, + std::make_unique( + Envoy::Config::Metadata::metadataValue(&data.metadata(), filter_, path_))}; + } + +private: + static std::vector initializePath( + const Protobuf::RepeatedPtrField& segments) { + std::vector path; + for (const auto& seg : segments) { + path.push_back(seg.key()); + } + return path; + } + + const std::string filter_; + const std::vector path_; +}; + +template +class DynamicMetadataInputBaseFactory : public Matcher::DataInputFactory { +public: + std::string name() const override { return "envoy.matching.inputs.dynamic_metadata"; } + + Matcher::DataInputFactoryCb + createDataInputFactoryCb(const Protobuf::Message& message, + ProtobufMessage::ValidationVisitor& validation_visitor) override { + const auto& typed_config = MessageUtil::downcastAndValidate< + const envoy::extensions::matching::common_inputs::network::v3::DynamicMetadataInput&>( + message, validation_visitor); + auto config_ptr = std::make_shared< + envoy::extensions::matching::common_inputs::network::v3::DynamicMetadataInput>( + typed_config); + return [config_ptr] { + return std::make_unique>(*config_ptr); + }; + }; + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique< + envoy::extensions::matching::common_inputs::network::v3::DynamicMetadataInput>(); + } +}; + +DECLARE_FACTORY(HttpDymanicMetadataInputFactory); + +} // namespace MetadataInput +} // namespace Http +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/input_matchers/metadata/BUILD b/source/extensions/matching/input_matchers/metadata/BUILD new file mode 100644 index 000000000000..91710ef4ab89 --- /dev/null +++ b/source/extensions/matching/input_matchers/metadata/BUILD @@ -0,0 +1,36 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "metadata_lib", + srcs = ["matcher.cc"], + hdrs = ["matcher.h"], + deps = [ + "//envoy/matcher:matcher_interface", + "//source/common/common:matchers_lib", + "//source/extensions/matching/http/metadata_input:metadata_input_lib", + "@envoy_api//envoy/extensions/matching/input_matchers/metadata/v3:pkg_cc_proto", + "@envoy_api//envoy/type/matcher/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":metadata_lib", + "//envoy/matcher:matcher_interface", + "//envoy/registry", + "//envoy/server:factory_context_interface", + "@envoy_api//envoy/extensions/matching/input_matchers/metadata/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/matching/input_matchers/metadata/config.cc b/source/extensions/matching/input_matchers/metadata/config.cc new file mode 100644 index 000000000000..6b78ba7a8e17 --- /dev/null +++ b/source/extensions/matching/input_matchers/metadata/config.cc @@ -0,0 +1,29 @@ +#include "source/extensions/matching/input_matchers/metadata/config.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace InputMatchers { +namespace Metadata { + +Envoy::Matcher::InputMatcherFactoryCb +Config::createInputMatcherFactoryCb(const Protobuf::Message& config, + Server::Configuration::ServerFactoryContext& factory_context) { + const auto& matcher_config = MessageUtil::downcastAndValidate< + const envoy::extensions::matching::input_matchers::metadata::v3::Metadata&>( + config, factory_context.messageValidationVisitor()); + const auto& value = matcher_config.value(); + const auto value_matcher = Envoy::Matchers::ValueMatcher::create(value, factory_context); + const bool invert = matcher_config.invert(); + return [value_matcher, invert]() { return std::make_unique(value_matcher, invert); }; +} +/** + * Static registration for the Metadata matcher. @see RegisterFactory. + */ +REGISTER_FACTORY(Config, Envoy::Matcher::InputMatcherFactory); + +} // namespace Metadata +} // namespace InputMatchers +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/input_matchers/metadata/config.h b/source/extensions/matching/input_matchers/metadata/config.h new file mode 100644 index 000000000000..6b6207c8bc0f --- /dev/null +++ b/source/extensions/matching/input_matchers/metadata/config.h @@ -0,0 +1,33 @@ +#pragma once + +#include "envoy/extensions/matching/input_matchers/metadata/v3/metadata.pb.h" +#include "envoy/extensions/matching/input_matchers/metadata/v3/metadata.pb.validate.h" +#include "envoy/matcher/matcher.h" +#include "envoy/server/factory_context.h" + +#include "source/common/protobuf/utility.h" +#include "source/extensions/matching/input_matchers/metadata/matcher.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace InputMatchers { +namespace Metadata { + +class Config : public Envoy::Matcher::InputMatcherFactory { +public: + Envoy::Matcher::InputMatcherFactoryCb createInputMatcherFactoryCb( + const Protobuf::Message& config, + Server::Configuration::ServerFactoryContext& factory_context) override; + + std::string name() const override { return "envoy.matching.matchers.metadata_matcher"; } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } +}; +} // namespace Metadata +} // namespace InputMatchers +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/input_matchers/metadata/matcher.cc b/source/extensions/matching/input_matchers/metadata/matcher.cc new file mode 100644 index 000000000000..6ede36a3f174 --- /dev/null +++ b/source/extensions/matching/input_matchers/metadata/matcher.cc @@ -0,0 +1,28 @@ +#include "source/extensions/matching/input_matchers/metadata/matcher.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace InputMatchers { +namespace Metadata { + +Matcher::Matcher(const Envoy::Matchers::ValueMatcherConstSharedPtr value_matcher, const bool invert) + : value_matcher_(value_matcher), invert_(invert) {} + +bool Matcher::match(const Envoy::Matcher::MatchingDataType& input) { + if (auto* ptr = absl::get_if>(&input); + ptr != nullptr) { + const Matching::Http::MetadataInput::MetadataMatchData* match_data = + dynamic_cast(ptr->get()); + if (match_data != nullptr) { + return value_matcher_->match(match_data->value_) ^ invert_; + } + } + return false; +} + +} // namespace Metadata +} // namespace InputMatchers +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/input_matchers/metadata/matcher.h b/source/extensions/matching/input_matchers/metadata/matcher.h new file mode 100644 index 000000000000..e6e8a356c7b1 --- /dev/null +++ b/source/extensions/matching/input_matchers/metadata/matcher.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "envoy/extensions/matching/input_matchers/metadata/v3/metadata.pb.h" +#include "envoy/matcher/matcher.h" +#include "envoy/type/matcher/v3/value.pb.h" + +#include "source/common/common/matchers.h" +#include "source/extensions/matching/http/metadata_input/meta_input.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace InputMatchers { +namespace Metadata { + +class Matcher : public Envoy::Matcher::InputMatcher, Logger::Loggable { +public: + Matcher(const Envoy::Matchers::ValueMatcherConstSharedPtr, const bool); + bool match(const Envoy::Matcher::MatchingDataType& input) override; + +private: + Envoy::Matchers::ValueMatcherConstSharedPtr value_matcher_; + bool invert_; +}; + +} // namespace Metadata +} // namespace InputMatchers +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/network/dns_resolver/apple/apple_dns_impl.cc b/source/extensions/network/dns_resolver/apple/apple_dns_impl.cc index b4d41989a604..cf2694c66096 100644 --- a/source/extensions/network/dns_resolver/apple/apple_dns_impl.cc +++ b/source/extensions/network/dns_resolver/apple/apple_dns_impl.cc @@ -216,9 +216,15 @@ std::list& AppleDnsResolverImpl::PendingResolution::finalAddressLis pending_response_.all_responses_.insert(pending_response_.all_responses_.end(), pending_response_.v4_responses_.begin(), pending_response_.v4_responses_.end()); - pending_response_.all_responses_.insert(pending_response_.all_responses_.end(), - pending_response_.v6_responses_.begin(), - pending_response_.v6_responses_.end()); + if (!Runtime::runtimeFeatureEnabled("envoy.reloadable_features.prefer_ipv6_dns_on_macos")) { + pending_response_.all_responses_.insert(pending_response_.all_responses_.end(), + pending_response_.v6_responses_.begin(), + pending_response_.v6_responses_.end()); + } else { + pending_response_.all_responses_.insert(pending_response_.all_responses_.begin(), + pending_response_.v6_responses_.begin(), + pending_response_.v6_responses_.end()); + } return pending_response_.all_responses_; } IS_ENVOY_BUG("unexpected DnsLookupFamily enum"); diff --git a/source/extensions/network/dns_resolver/cares/dns_impl.cc b/source/extensions/network/dns_resolver/cares/dns_impl.cc index 46986aadeb3a..f3c662bcec7c 100644 --- a/source/extensions/network/dns_resolver/cares/dns_impl.cc +++ b/source/extensions/network/dns_resolver/cares/dns_impl.cc @@ -216,7 +216,7 @@ void DnsResolverImpl::AddrInfoPendingResolution::onAresGetAddrInfoCallback( if (status == ARES_SUCCESS) { pending_response_.status_ = ResolutionStatus::Success; - pending_response_.details_ = "cares_success"; + pending_response_.details_ = absl::StrCat("cares_success:", ares_strerror(status)); if (addrinfo != nullptr && addrinfo->nodes != nullptr) { bool can_process_v4 = @@ -265,10 +265,10 @@ void DnsResolverImpl::AddrInfoPendingResolution::onAresGetAddrInfoCallback( // Treat `ARES_ENODATA` or `ARES_ENOTFOUND` here as success to populate back the // "empty records" response. pending_response_.status_ = ResolutionStatus::Success; - pending_response_.details_ = "cares_norecords"; + pending_response_.details_ = absl::StrCat("cares_norecords:", ares_strerror(status)); ASSERT(addrinfo == nullptr); } else { - pending_response_.details_ = "cares_failure"; + pending_response_.details_ = absl::StrCat("cares_failure:", ares_strerror(status)); } if (timeouts > 0) { @@ -583,7 +583,7 @@ class CaresDnsResolverFactory : public DnsResolverFactory, resolvers.reserve(resolver_addrs.size()); for (const auto& resolver_addr : resolver_addrs) { auto address_or_error = Network::Address::resolveProtoAddress(resolver_addr); - RETURN_IF_STATUS_NOT_OK(address_or_error); + RETURN_IF_NOT_OK_REF(address_or_error.status()); resolvers.push_back(std::move(address_or_error.value())); } } diff --git a/source/extensions/tracers/opentelemetry/http_trace_exporter.cc b/source/extensions/tracers/opentelemetry/http_trace_exporter.cc index 1ff2d2c7c867..98a121a21ff4 100644 --- a/source/extensions/tracers/opentelemetry/http_trace_exporter.cc +++ b/source/extensions/tracers/opentelemetry/http_trace_exporter.cc @@ -61,8 +61,11 @@ bool OpenTelemetryHttpTraceExporter::log(const ExportTraceServiceRequest& reques } message->body().add(request_body); - const auto options = Http::AsyncClient::RequestOptions().setTimeout(std::chrono::milliseconds( - DurationUtil::durationToMilliseconds(http_service_.http_uri().timeout()))); + const auto options = + Http::AsyncClient::RequestOptions() + .setTimeout(std::chrono::milliseconds( + DurationUtil::durationToMilliseconds(http_service_.http_uri().timeout()))) + .setDiscardResponseBody(true); Http::AsyncClient::Request* in_flight_request = thread_local_cluster->httpAsyncClient().send(std::move(message), *this, options); diff --git a/source/extensions/transport_sockets/alts/BUILD b/source/extensions/transport_sockets/alts/BUILD index f1d4c0b33e01..fe03259a7338 100644 --- a/source/extensions/transport_sockets/alts/BUILD +++ b/source/extensions/transport_sockets/alts/BUILD @@ -1,4 +1,4 @@ -load("@com_github_rules_proto_grpc//cpp:defs.bzl", "cpp_grpc_library") +load("@rules_proto_grpc//cpp:defs.bzl", "cpp_grpc_library") load( "//bazel:envoy_build_system.bzl", "envoy_cc_extension", diff --git a/source/extensions/transport_sockets/http_11_proxy/BUILD b/source/extensions/transport_sockets/http_11_proxy/BUILD index f6a709461b7c..78df614fb285 100644 --- a/source/extensions/transport_sockets/http_11_proxy/BUILD +++ b/source/extensions/transport_sockets/http_11_proxy/BUILD @@ -36,6 +36,7 @@ envoy_cc_library( "//source/common/buffer:buffer_lib", "//source/common/common:scalar_to_byte_vector_lib", "//source/common/common:utility_lib", + "//source/common/config:well_known_names", "//source/common/http/http1:balsa_parser_lib", "//source/common/http/http1:legacy_parser_lib", "//source/common/network:address_lib", diff --git a/source/extensions/transport_sockets/http_11_proxy/config.cc b/source/extensions/transport_sockets/http_11_proxy/config.cc index a54ead186aac..0e95e6a34743 100644 --- a/source/extensions/transport_sockets/http_11_proxy/config.cc +++ b/source/extensions/transport_sockets/http_11_proxy/config.cc @@ -25,7 +25,7 @@ UpstreamHttp11ConnectSocketConfigFactory::createTransportSocketFactory( outer_config.transport_socket(), context.messageValidationVisitor(), inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(std::move(factory_or_error.value())); } diff --git a/source/extensions/transport_sockets/http_11_proxy/connect.cc b/source/extensions/transport_sockets/http_11_proxy/connect.cc index d464734b33c3..5e1c10f7d5c7 100644 --- a/source/extensions/transport_sockets/http_11_proxy/connect.cc +++ b/source/extensions/transport_sockets/http_11_proxy/connect.cc @@ -7,6 +7,7 @@ #include "source/common/buffer/buffer_impl.h" #include "source/common/common/scalar_to_byte_vector.h" #include "source/common/common/utility.h" +#include "source/common/config/well_known_names.h" #include "source/common/network/address_impl.h" #include "source/common/runtime/runtime_features.h" @@ -29,12 +30,35 @@ bool UpstreamHttp11ConnectSocket::isValidConnectResponse(absl::string_view respo UpstreamHttp11ConnectSocket::UpstreamHttp11ConnectSocket( Network::TransportSocketPtr&& transport_socket, - Network::TransportSocketOptionsConstSharedPtr options) + Network::TransportSocketOptionsConstSharedPtr options, + std::shared_ptr host) : PassthroughSocket(std::move(transport_socket)), options_(options) { - if (options_ && options_->http11ProxyInfo() && transport_socket_->ssl()) { - header_buffer_.add( - absl::StrCat("CONNECT ", options_->http11ProxyInfo()->hostname, ":443 HTTP/1.1\r\n\r\n")); - need_to_strip_connect_response_ = true; + // If the filter state metadata has populated the relevant entries in the transport socket + // options, we want to maintain the original behavior of this transport socket. + if (options_ && options_->http11ProxyInfo()) { + if (transport_socket_->ssl()) { + header_buffer_.add( + absl::StrCat("CONNECT ", options_->http11ProxyInfo()->hostname, ":443 HTTP/1.1\r\n\r\n")); + need_to_strip_connect_response_ = true; + } + + return; + } + + // The absence of proxy info from the transport socket options means that we should use the host + // address of the provided HostDescription if it has the appropriate metadata set. + for (auto& metadata : {host->metadata(), host->localityMetadata()}) { + if (metadata == nullptr) { + continue; + } + + const bool has_proxy_addr = metadata->typed_filter_metadata().contains( + Config::MetadataFilters::get().ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR); + if (has_proxy_addr) { + header_buffer_.add( + absl::StrCat("CONNECT ", host->address()->asStringView(), " HTTP/1.1\r\n\r\n")); + need_to_strip_connect_response_ = true; + } } } @@ -139,7 +163,7 @@ Network::TransportSocketPtr UpstreamHttp11ConnectSocketFactory::createTransportS if (inner_socket == nullptr) { return nullptr; } - return std::make_unique(std::move(inner_socket), options); + return std::make_unique(std::move(inner_socket), options, host); } void UpstreamHttp11ConnectSocketFactory::hashKey( diff --git a/source/extensions/transport_sockets/http_11_proxy/connect.h b/source/extensions/transport_sockets/http_11_proxy/connect.h index 2e06915a11f1..d82459182503 100644 --- a/source/extensions/transport_sockets/http_11_proxy/connect.h +++ b/source/extensions/transport_sockets/http_11_proxy/connect.h @@ -28,7 +28,8 @@ class UpstreamHttp11ConnectSocket : public TransportSockets::PassthroughSocket, size_t& bytes_processed); UpstreamHttp11ConnectSocket(Network::TransportSocketPtr&& transport_socket, - Network::TransportSocketOptionsConstSharedPtr options); + Network::TransportSocketOptionsConstSharedPtr options, + std::shared_ptr host); void setTransportSocketCallbacks(Network::TransportSocketCallbacks& callbacks) override; Network::IoResult doWrite(Buffer::Instance& buffer, bool end_stream) override; diff --git a/source/extensions/transport_sockets/internal_upstream/config.cc b/source/extensions/transport_sockets/internal_upstream/config.cc index dfef2a21e662..d8b31db91e9b 100644 --- a/source/extensions/transport_sockets/internal_upstream/config.cc +++ b/source/extensions/transport_sockets/internal_upstream/config.cc @@ -40,7 +40,7 @@ class InternalUpstreamConfigFactory inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(context, outer_config, std::move(factory_or_error.value())); } diff --git a/source/extensions/transport_sockets/proxy_protocol/config.cc b/source/extensions/transport_sockets/proxy_protocol/config.cc index 05551ad61f28..fcde4faafad4 100644 --- a/source/extensions/transport_sockets/proxy_protocol/config.cc +++ b/source/extensions/transport_sockets/proxy_protocol/config.cc @@ -26,7 +26,7 @@ UpstreamProxyProtocolSocketConfigFactory::createTransportSocketFactory( outer_config.transport_socket(), context.messageValidationVisitor(), inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique( std::move(factory_or_error.value()), outer_config.config(), context.statsScope()); } diff --git a/source/extensions/transport_sockets/starttls/config.cc b/source/extensions/transport_sockets/starttls/config.cc index 7d4552a7a1e6..a2f0722df7e6 100644 --- a/source/extensions/transport_sockets/starttls/config.cc +++ b/source/extensions/transport_sockets/starttls/config.cc @@ -20,11 +20,11 @@ DownstreamStartTlsSocketFactory::createTransportSocketFactory( auto raw_or_error = raw_socket_config_factory.createTransportSocketFactory( outer_config.cleartext_socket_config(), context, server_names); - RETURN_IF_STATUS_NOT_OK(raw_or_error); + RETURN_IF_NOT_OK_REF(raw_or_error.status()); auto factory_or_error = tls_socket_config_factory.createTransportSocketFactory( outer_config.tls_socket_config(), context, server_names); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(std::move(raw_or_error.value()), std::move(factory_or_error.value())); @@ -43,11 +43,11 @@ UpstreamStartTlsSocketFactory::createTransportSocketFactory( auto raw_or_error = raw_socket_config_factory.createTransportSocketFactory( outer_config.cleartext_socket_config(), context); - RETURN_IF_STATUS_NOT_OK(raw_or_error); + RETURN_IF_NOT_OK_REF(raw_or_error.status()); auto factory_or_error = tls_socket_config_factory.createTransportSocketFactory( outer_config.tls_socket_config(), context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(std::move(raw_or_error.value()), std::move(factory_or_error.value())); diff --git a/source/extensions/transport_sockets/tap/config.cc b/source/extensions/transport_sockets/tap/config.cc index 2bb7c37f22f7..b1417d9beda3 100644 --- a/source/extensions/transport_sockets/tap/config.cc +++ b/source/extensions/transport_sockets/tap/config.cc @@ -47,7 +47,7 @@ UpstreamTapSocketConfigFactory::createTransportSocketFactory( outer_config.transport_socket(), context.messageValidationVisitor(), inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); auto& server_context = context.serverFactoryContext(); return std::make_unique( @@ -72,7 +72,7 @@ DownstreamTapSocketConfigFactory::createTransportSocketFactory( outer_config.transport_socket(), context.messageValidationVisitor(), inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context, server_names); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); auto& server_context = context.serverFactoryContext(); return std::make_unique( outer_config, diff --git a/source/extensions/transport_sockets/tcp_stats/config.cc b/source/extensions/transport_sockets/tcp_stats/config.cc index f3702c051ad3..938fc6c14e63 100644 --- a/source/extensions/transport_sockets/tcp_stats/config.cc +++ b/source/extensions/transport_sockets/tcp_stats/config.cc @@ -93,7 +93,7 @@ class UpstreamTcpStatsConfigFactory inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(context, outer_config, std::move(factory_or_error.value())); } @@ -119,7 +119,7 @@ class DownstreamTcpStatsConfigFactory inner_config_factory); auto factory_or_error = inner_config_factory.createTransportSocketFactory( *inner_factory_config, context, server_names); - RETURN_IF_STATUS_NOT_OK(factory_or_error); + RETURN_IF_NOT_OK_REF(factory_or_error.status()); return std::make_unique(context, outer_config, std::move(factory_or_error.value())); } diff --git a/source/extensions/upstreams/http/config.cc b/source/extensions/upstreams/http/config.cc index ce9330bd4661..8acda93047c8 100644 --- a/source/extensions/upstreams/http/config.cc +++ b/source/extensions/upstreams/http/config.cc @@ -189,11 +189,11 @@ ProtocolOptionsConfigImpl::createProtocolOptionsConfig( const envoy::extensions::upstreams::http::v3::HttpProtocolOptions& options, Server::Configuration::ServerFactoryContext& server_context) { auto options_or_error = Http2::Utility::initializeAndValidateOptions(getHttp2Options(options)); - RETURN_IF_STATUS_NOT_OK(options_or_error); + RETURN_IF_NOT_OK_REF(options_or_error.status()); auto cache_options_or_error = getAlternateProtocolsCacheOptions(options, server_context); - RETURN_IF_STATUS_NOT_OK(cache_options_or_error); + RETURN_IF_NOT_OK_REF(cache_options_or_error.status()); auto validator_factory_or_error = createHeaderValidatorFactory(options, server_context); - RETURN_IF_STATUS_NOT_OK(validator_factory_or_error); + RETURN_IF_NOT_OK_REF(validator_factory_or_error.status()); return std::shared_ptr(new ProtocolOptionsConfigImpl( options, options_or_error.value(), std::move(validator_factory_or_error.value()), cache_options_or_error.value(), server_context)); @@ -208,7 +208,7 @@ ProtocolOptionsConfigImpl::createProtocolOptionsConfig( bool use_downstream_protocol, bool use_http2, ProtobufMessage::ValidationVisitor& validation_visitor) { auto options_or_error = Http2::Utility::initializeAndValidateOptions(http2_options); - RETURN_IF_STATUS_NOT_OK(options_or_error); + RETURN_IF_NOT_OK_REF(options_or_error.status()); return std::shared_ptr(new ProtocolOptionsConfigImpl( http1_settings, options_or_error.value(), common_options, upstream_options, use_downstream_protocol, use_http2, validation_visitor)); diff --git a/source/extensions/upstreams/http/http/upstream_request.h b/source/extensions/upstreams/http/http/upstream_request.h index db8adfc2cc14..f8c714160774 100644 --- a/source/extensions/upstreams/http/http/upstream_request.h +++ b/source/extensions/upstreams/http/http/upstream_request.h @@ -73,7 +73,7 @@ class HttpUpstream : public Router::GenericUpstream, public Envoy::Http::StreamC void encodeTrailers(const Envoy::Http::RequestTrailerMap& trailers) override { request_encoder_->encodeTrailers(trailers); } - void enableHalfClose() override { request_encoder_->enableTcpTunneling(); } + void enableTcpTunneling() override { request_encoder_->enableTcpTunneling(); } void readDisable(bool disable) override { request_encoder_->getStream().readDisable(disable); } diff --git a/source/extensions/upstreams/http/tcp/upstream_request.h b/source/extensions/upstreams/http/tcp/upstream_request.h index 3a0df2815529..1823c48e41bb 100644 --- a/source/extensions/upstreams/http/tcp/upstream_request.h +++ b/source/extensions/upstreams/http/tcp/upstream_request.h @@ -78,7 +78,7 @@ class TcpUpstream : public Router::GenericUpstream, void encodeMetadata(const Envoy::Http::MetadataMapVector&) override {} Envoy::Http::Status encodeHeaders(const Envoy::Http::RequestHeaderMap&, bool end_stream) override; void encodeTrailers(const Envoy::Http::RequestTrailerMap&) override; - void enableHalfClose() override {} + void enableTcpTunneling() override {} void readDisable(bool disable) override; void resetStream() override; void setAccount(Buffer::BufferMemoryAccountSharedPtr) override {} diff --git a/source/extensions/upstreams/http/udp/upstream_request.h b/source/extensions/upstreams/http/udp/upstream_request.h index 5a17695d269c..34fab9e45da2 100644 --- a/source/extensions/upstreams/http/udp/upstream_request.h +++ b/source/extensions/upstreams/http/udp/upstream_request.h @@ -77,7 +77,7 @@ class UdpUpstream : public Router::GenericUpstream, void encodeTrailers(const Envoy::Http::RequestTrailerMap&) override {} void readDisable(bool) override {} void resetStream() override; - void enableHalfClose() override {} + void enableTcpTunneling() override {} void setAccount(Buffer::BufferMemoryAccountSharedPtr) override {} const StreamInfo::BytesMeterSharedPtr& bytesMeter() override { return bytes_meter_; } diff --git a/source/server/admin/admin.h b/source/server/admin/admin.h index 92db9a75a6ad..80a91efc3ea0 100644 --- a/source/server/admin/admin.h +++ b/source/server/admin/admin.h @@ -148,6 +148,7 @@ class AdminImpl : public Admin, absl::optional maxConnectionDuration() const override { return max_connection_duration_; } + bool http1SafeMaxConnectionDuration() const override { return false; } uint32_t maxRequestHeadersKb() const override { return max_request_headers_kb_; } uint32_t maxRequestHeadersCount() const override { return max_request_headers_count_; } std::chrono::milliseconds streamIdleTimeout() const override { return {}; } diff --git a/source/server/api_listener_impl.cc b/source/server/api_listener_impl.cc index a9dfa065d89c..7f5d4e8fe9ad 100644 --- a/source/server/api_listener_impl.cc +++ b/source/server/api_listener_impl.cc @@ -45,7 +45,7 @@ absl::StatusOr> HttpApiListener::create(const envoy::config::listener::v3::Listener& config, Server::Instance& server, const std::string& name) { auto address_or_error = Network::Address::resolveProtoAddress(config.address()); - RETURN_IF_STATUS_NOT_OK(address_or_error); + RETURN_IF_NOT_OK_REF(address_or_error.status()); return std::unique_ptr( new HttpApiListener(std::move(address_or_error.value()), config, server, name)); } diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index 883b47531507..8a9f763d4a53 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -140,7 +140,7 @@ absl::Status MainImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& ENVOY_LOG(debug, "listener #{}:", i); absl::StatusOr update_or_error = server.listenerManager().addOrUpdateListener(listeners[i], "", false); - RETURN_IF_STATUS_NOT_OK(update_or_error); + RETURN_IF_NOT_OK_REF(update_or_error.status()); } RETURN_IF_NOT_OK(initializeWatchdogs(bootstrap, server)); // This has to happen after ClusterManager initialization, as it depends on config from diff --git a/source/server/options_impl.cc b/source/server/options_impl.cc index eaa6005bb260..b72e6237249f 100644 --- a/source/server/options_impl.cc +++ b/source/server/options_impl.cc @@ -214,7 +214,12 @@ OptionsImpl::OptionsImpl(std::vector args, log_format_ = log_format.getValue(); log_format_set_ = log_format.isSet(); log_format_escaped_ = log_format_escaped.getValue(); + enable_fine_grain_logging_ = enable_fine_grain_logging.getValue(); + if (enable_fine_grain_logging_ && !component_log_level.getValue().empty()) { + throw MalformedArgvException( + "error: --component-log-level will not work with --enable-fine-grain-logging"); + } parseComponentLogLevels(component_log_level.getValue()); diff --git a/source/server/server.cc b/source/server/server.cc index 2b43921d973a..a8fbc195549e 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -503,7 +503,7 @@ absl::Status InstanceBase::initializeOrThrow(Network::Address::InstanceConstShar // stats. auto producer_or_error = Stats::TagProducerImpl::createTagProducer(bootstrap_.stats_config(), options_.statsTags()); - RETURN_IF_STATUS_NOT_OK(producer_or_error); + RETURN_IF_NOT_OK_REF(producer_or_error.status()); stats_store_.setTagProducer(std::move(producer_or_error.value())); stats_store_.setStatsMatcher(std::make_unique( bootstrap_.stats_config(), stats_store_.symbolTable(), server_contexts_)); diff --git a/test/common/common/utility_test.cc b/test/common/common/utility_test.cc index 3e9550a546d6..10e52d189f56 100644 --- a/test/common/common/utility_test.cc +++ b/test/common/common/utility_test.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -1043,6 +1044,56 @@ TEST(DateFormatter, FromTime) { const SystemTime time2(std::chrono::seconds(0)); EXPECT_EQ("1970-01-01T00:00:00.000Z", DateFormatter("%Y-%m-%dT%H:%M:%S.000Z").fromTime(time2)); EXPECT_EQ("aaa00", DateFormatter(std::string(3, 'a') + "%H").fromTime(time2)); + + const SystemTime time3(std::chrono::milliseconds(1522796769321)); + EXPECT_EQ("2018-04-03T23:06:09.321Z", DateFormatter("%Y-%m-%dT%H:%M:%E3SZ").fromTime(time3)); + EXPECT_EQ("aaa23", DateFormatter(std::string(3, 'a') + "%H").fromTime(time1)); + const SystemTime time4(std::chrono::seconds(0)); + EXPECT_EQ("1970-01-01T00:00:00.000Z", DateFormatter("%Y-%m-%dT%H:%M:%E3SZ").fromTime(time4)); + EXPECT_EQ("aaa00", DateFormatter(std::string(3, 'a') + "%H").fromTime(time2)); + + const SystemTime time5(std::chrono::milliseconds(321)); + EXPECT_EQ("1970-01-01T00:00:00.321Z", DateFormatter("%Y-%m-%dT%H:%M:%E3SZ").fromTime(time5)); + EXPECT_EQ("aaa00", DateFormatter(std::string(3, 'a') + "%H").fromTime(time2)); +} + +TEST(DateFormatter, DateFormatterVsAbslFormatTime) { + const std::string format = "%Y-%m-%dT%H:%M:%E3SZ %Ez %E*z %E8S %E*S %E5f %E*f %E4Y %ET"; + + SystemTime zero_time(std::chrono::seconds(0)); + + EXPECT_EQ(DateFormatter(format).fromTime(zero_time), + absl::FormatTime(format, absl::FromChrono(zero_time), absl::UTCTimeZone())); + + std::mt19937 prng(1); + std::uniform_int_distribution distribution(-10, 20); + + SystemTime now = std::chrono::system_clock::now(); // NO_CHECK_FORMAT(real_time) + + for (size_t i = 0; i < 20; i++) { + auto time = now + std::chrono::milliseconds(static_cast(distribution(prng))); + // UTC time zone. + EXPECT_EQ(DateFormatter(format).fromTime(time), + absl::FormatTime(format, absl::FromChrono(time), absl::UTCTimeZone())); + + // Local time zone. + EXPECT_EQ(DateFormatter(format, true).fromTime(time), + absl::FormatTime(format, absl::FromChrono(time), absl::LocalTimeZone())); + } +} + +TEST(DateFormatter, HybridAbsl) { + const std::string format = "%Y-%m-%dT%H:%M:%E3SZ %E6S %E*S %E4f %E*f %S. %s %3f %6f %9f"; + + const SystemTime time1(std::chrono::seconds(1522796769) + std::chrono::microseconds(123450)); + + EXPECT_EQ( + "2018-04-03T23:06:09.123Z 09.123450 09.12345 1234 12345 09. 1522796769 123 123450 123450000", + DateFormatter(format).fromTime(time1)); + + const SystemTime time2(std::chrono::seconds(0)); + EXPECT_EQ("1970-01-01T00:00:00.000Z 00.000000 00 0000 0 00. 0 000 000000 000000000", + DateFormatter(format).fromTime(time2)); } TEST(DateFormatter, FromTimeLocalTimeZone) { @@ -1084,9 +1135,6 @@ TEST(DateFormatter, ParseLongString) { EXPECT_EQ(expected_output, output); } -// Verify that two DateFormatter patterns with the same ??? patterns but -// different format strings don't false share cache entries. This is a -// regression test for when they did. TEST(DateFormatter, FromTimeSameWildcard) { const SystemTime time1(std::chrono::seconds(1522796769) + std::chrono::milliseconds(142)); EXPECT_EQ("2018-04-03T23:06:09.000Z142", diff --git a/test/common/filter/config_discovery_impl_test.cc b/test/common/filter/config_discovery_impl_test.cc index cf8e30503fce..cb580db0ffde 100644 --- a/test/common/filter/config_discovery_impl_test.cc +++ b/test/common/filter/config_discovery_impl_test.cc @@ -275,7 +275,7 @@ class FilterConfigDiscoveryImplTest : public FilterConfigDiscoveryTestBase { // HTTP filter test class HttpFilterConfigDiscoveryImplTest : public FilterConfigDiscoveryImplTest< - NamedHttpFilterFactoryCb, Server::Configuration::FactoryContext, + HttpFilterFactoryCb, Server::Configuration::FactoryContext, HttpFilterConfigProviderManagerImpl, TestHttpFilterFactory, Server::Configuration::NamedHttpFilterConfigFactory, Server::Configuration::MockFactoryContext> { @@ -292,7 +292,7 @@ class HttpFilterConfigDiscoveryImplTest // Upstream HTTP filter test class HttpUpstreamFilterConfigDiscoveryImplTest : public FilterConfigDiscoveryImplTest< - NamedHttpFilterFactoryCb, Server::Configuration::UpstreamFactoryContext, + HttpFilterFactoryCb, Server::Configuration::UpstreamFactoryContext, UpstreamHttpFilterConfigProviderManagerImpl, TestHttpFilterFactory, Server::Configuration::UpstreamHttpFilterConfigFactory, Server::Configuration::MockUpstreamFactoryContext> { diff --git a/test/common/formatter/command_extension.cc b/test/common/formatter/command_extension.cc index aaa57140ce0b..b196a924b4c5 100644 --- a/test/common/formatter/command_extension.cc +++ b/test/common/formatter/command_extension.cc @@ -16,8 +16,8 @@ TestFormatter::formatValueWithContext(const HttpFormatterContext& context, return ValueUtil::stringValue(formatWithContext(context, stream_info).value()); } -FormatterProviderPtr TestCommandParser::parse(const std::string& command, const std::string&, - absl::optional&) const { +FormatterProviderPtr TestCommandParser::parse(absl::string_view command, absl::string_view, + absl::optional) const { if (command == "COMMAND_EXTENSION") { return std::make_unique(); } @@ -54,8 +54,8 @@ AdditionalFormatter::formatValueWithContext(const HttpFormatterContext& context, return ValueUtil::stringValue(formatWithContext(context, stream_info).value()); } -FormatterProviderPtr AdditionalCommandParser::parse(const std::string& command, const std::string&, - absl::optional&) const { +FormatterProviderPtr AdditionalCommandParser::parse(absl::string_view command, absl::string_view, + absl::optional) const { if (command == "ADDITIONAL_EXTENSION") { return std::make_unique(); } diff --git a/test/common/formatter/command_extension.h b/test/common/formatter/command_extension.h index ac922147c951..6b3e89b3342e 100644 --- a/test/common/formatter/command_extension.h +++ b/test/common/formatter/command_extension.h @@ -24,8 +24,8 @@ class TestFormatter : public FormatterProvider { class TestCommandParser : public CommandParser { public: - FormatterProviderPtr parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const override; + FormatterProviderPtr parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const override; }; class TestCommandFactory : public CommandParserFactory { @@ -52,8 +52,8 @@ class AdditionalFormatter : public FormatterProvider { class AdditionalCommandParser : public CommandParser { public: - FormatterProviderPtr parse(const std::string& command, const std::string& subcommand, - absl::optional& max_length) const override; + FormatterProviderPtr parse(absl::string_view command, absl::string_view subcommand, + absl::optional max_length) const override; }; class AdditionalCommandFactory : public CommandParserFactory { diff --git a/test/common/formatter/substitution_formatter_speed_test.cc b/test/common/formatter/substitution_formatter_speed_test.cc index e304dd5c52a7..30cfd83768d6 100644 --- a/test/common/formatter/substitution_formatter_speed_test.cc +++ b/test/common/formatter/substitution_formatter_speed_test.cc @@ -75,7 +75,8 @@ BENCHMARK(BM_AccessLogFormatterSetup); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_AccessLogFormatter(benchmark::State& state) { - MockTimeSystem time_system; + testing::NiceMock time_system; + std::unique_ptr stream_info = makeStreamInfo(time_system); static const char* LogFormat = "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% %START_TIME(%Y/%m/%dT%H:%M:%S%z %s)% " @@ -96,7 +97,8 @@ BENCHMARK(BM_AccessLogFormatter); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_StructAccessLogFormatter(benchmark::State& state) { - MockTimeSystem time_system; + testing::NiceMock time_system; + std::unique_ptr stream_info = makeStreamInfo(time_system); std::unique_ptr struct_formatter = makeStructFormatter(false); @@ -110,7 +112,8 @@ BENCHMARK(BM_StructAccessLogFormatter); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_TypedStructAccessLogFormatter(benchmark::State& state) { - MockTimeSystem time_system; + testing::NiceMock time_system; + std::unique_ptr stream_info = makeStreamInfo(time_system); std::unique_ptr typed_struct_formatter = makeStructFormatter(true); @@ -125,7 +128,8 @@ BENCHMARK(BM_TypedStructAccessLogFormatter); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_JsonAccessLogFormatter(benchmark::State& state) { - MockTimeSystem time_system; + testing::NiceMock time_system; + std::unique_ptr stream_info = makeStreamInfo(time_system); std::unique_ptr json_formatter = makeJsonFormatter(false); @@ -139,7 +143,8 @@ BENCHMARK(BM_JsonAccessLogFormatter); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_TypedJsonAccessLogFormatter(benchmark::State& state) { - MockTimeSystem time_system; + testing::NiceMock time_system; + std::unique_ptr stream_info = makeStreamInfo(time_system); std::unique_ptr typed_json_formatter = makeJsonFormatter(true); @@ -155,7 +160,7 @@ BENCHMARK(BM_TypedJsonAccessLogFormatter); // NOLINTNEXTLINE(readability-identifier-naming) static void BM_FormatterCommandParsing(benchmark::State& state) { const std::string token = "Listener:namespace:key"; - std::string listener, names, key; + absl::string_view listener, names, key; for (auto _ : state) { // NOLINT: Silences warning about dead store Formatter::SubstitutionFormatUtils::parseSubcommand(token, ':', listener, names, key); } diff --git a/test/common/formatter/substitution_formatter_test.cc b/test/common/formatter/substitution_formatter_test.cc index a9613ce63bf9..a87f2f447e53 100644 --- a/test/common/formatter/substitution_formatter_test.cc +++ b/test/common/formatter/substitution_formatter_test.cc @@ -165,20 +165,20 @@ REGISTER_FACTORY(TestSerializedStringFilterStateFactory, StreamInfo::FilterState // extracting tokens. TEST(SubstitutionFormatParser, commandParser) { std::vector tokens; - std::string token1; + absl::string_view token1; std::string command = "item1"; SubstitutionFormatUtils::parseSubcommand(command, ':', token1); ASSERT_EQ(token1, "item1"); - std::string token2; + absl::string_view token2; command = "item1:item2"; SubstitutionFormatUtils::parseSubcommand(command, ':', token1, token2); ASSERT_EQ(token1, "item1"); ASSERT_EQ(token2, "item2"); // Three tokens. - std::string token3; + absl::string_view token3; command = "item1?item2?item3"; SubstitutionFormatUtils::parseSubcommand(command, '?', token1, token2, token3); ASSERT_EQ(token1, "item1"); @@ -196,7 +196,7 @@ TEST(SubstitutionFormatParser, commandParser) { // Command string has 2 tokens but 3 are expected. // The third extracted token should be empty. command = "item1?item2"; - token3.erase(); + token3 = {}; SubstitutionFormatUtils::parseSubcommand(command, '?', token1, token2, token3); ASSERT_EQ(token1, "item1"); ASSERT_EQ(token2, "item2"); @@ -205,7 +205,7 @@ TEST(SubstitutionFormatParser, commandParser) { // Command string has 4 tokens. Get first 2 into the strings // and remaining 2 into a vector of strings. command = "item1?item2?item3?item4"; - std::vector bucket; + std::vector bucket; SubstitutionFormatUtils::parseSubcommand(command, '?', token1, token2, bucket); ASSERT_EQ(token1, "item1"); ASSERT_EQ(token2, "item2"); @@ -1087,7 +1087,6 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) { for (auto& precision : precisions) { const std::string sub_command = absl::StrCat(time_points[start_index], ":", time_points[end_index], ":", precision); - std::cout << sub_command << std::endl; StreamInfoFormatter duration_format("COMMON_DURATION", sub_command); if (start_index == end_index && start_index == 0) { @@ -1165,7 +1164,6 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) { const std::string sub_command = absl::StrCat(time_points[start_index], ":", time_points[end_index], ":", precision); - std::cout << sub_command << std::endl; StreamInfoFormatter duration_format("COMMON_DURATION", sub_command); @@ -1701,6 +1699,109 @@ TEST(SubstitutionFormatterTest, streamInfoFormatterWithSsl) { EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), ProtoEq(ValueUtil::nullValue())); } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256"); + auto connection_info = std::make_shared(); + std::vector expected_shas{ + "685a2db593d5f86d346cb1a297009c3b467ad77f1944aa799039a2fb3d531f3f", + "1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a"}; + auto joined_shas = absl::StrJoin(expected_shas, ","); + EXPECT_CALL(*connection_info, sha256PeerCertificateChainDigests()) + .WillRepeatedly(Return(expected_shas)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(joined_shas, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::stringValue(joined_shas))); + } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256"); + auto connection_info = std::make_shared(); + std::vector expected_shas; + EXPECT_CALL(*connection_info, sha256PeerCertificateChainDigests()) + .WillRepeatedly(Return(expected_shas)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } + { + NiceMock stream_info; + stream_info.downstream_connection_info_provider_->setSslConnection(nullptr); + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_256"); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1"); + auto connection_info = std::make_shared(); + std::vector expected_shas{ + "685a2db593d5f86d346cb1a297009c3b467ad77f1944aa799039a2fb3d531f3f", + "1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a"}; + auto joined_shas = absl::StrJoin(expected_shas, ","); + EXPECT_CALL(*connection_info, sha1PeerCertificateChainDigests()) + .WillRepeatedly(Return(expected_shas)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(joined_shas, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::stringValue(joined_shas))); + } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1"); + auto connection_info = std::make_shared(); + std::vector expected_shas; + EXPECT_CALL(*connection_info, sha1PeerCertificateChainDigests()) + .WillRepeatedly(Return(expected_shas)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } + { + NiceMock stream_info; + stream_info.downstream_connection_info_provider_->setSslConnection(nullptr); + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_FINGERPRINTS_1"); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_SERIALS"); + auto connection_info = std::make_shared(); + std::vector serial_numbers{"b8b5ecc898f2124a", "9bf18bd79b46589902639871"}; + auto joined_serials = absl::StrJoin(serial_numbers, ","); + EXPECT_CALL(*connection_info, serialNumbersPeerCertificates()) + .WillRepeatedly(Return(serial_numbers)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(joined_serials, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::stringValue(joined_serials))); + } + { + NiceMock stream_info; + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_SERIALS"); + std::vector empty_vec; + auto connection_info = std::make_shared(); + EXPECT_CALL(*connection_info, serialNumbersPeerCertificates()) + .WillRepeatedly(Return(empty_vec)); + stream_info.downstream_connection_info_provider_->setSslConnection(connection_info); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } + { + NiceMock stream_info; + stream_info.downstream_connection_info_provider_->setSslConnection(nullptr); + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_CHAIN_SERIALS"); + EXPECT_EQ(absl::nullopt, upstream_format.formatWithContext({}, stream_info)); + EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info), + ProtoEq(ValueUtil::nullValue())); + } { NiceMock stream_info; StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_ISSUER"); diff --git a/test/common/http/async_client_impl_test.cc b/test/common/http/async_client_impl_test.cc index 2d5bc5892611..0bd9c5c5e502 100644 --- a/test/common/http/async_client_impl_test.cc +++ b/test/common/http/async_client_impl_test.cc @@ -2195,6 +2195,18 @@ TEST_F(AsyncClientImplTest, DumpState) { EXPECT_CALL(stream_callbacks_, onReset()); } +TEST_F(AsyncClientImplTest, ParentStreamInfo) { + NiceMock parent_stream_info; + auto options = AsyncClient::StreamOptions(); + options.parent_context.stream_info = &parent_stream_info; + AsyncClient::Stream* stream = client_.start(stream_callbacks_, options); + EXPECT_TRUE(stream->streamInfo().parentStreamInfo().has_value()); + EXPECT_EQ(stream->streamInfo().parentStreamInfo().ptr(), + dynamic_cast(&parent_stream_info)); + stream->streamInfo().clearParentStreamInfo(); + EXPECT_FALSE(stream->streamInfo().parentStreamInfo().has_value()); +} + } // namespace // Must not be in anonymous namespace for friend to work. diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index 065b4d53f377..59a5012ae857 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -153,6 +153,9 @@ class FuzzConfig : public ConnectionManagerConfig { absl::optional maxConnectionDuration() const override { return max_connection_duration_; } + bool http1SafeMaxConnectionDuration() const override { + return http1_safe_max_connection_duration_; + } absl::optional maxStreamDuration() const override { return max_stream_duration_; } @@ -276,6 +279,7 @@ class FuzzConfig : public ConnectionManagerConfig { uint32_t max_request_headers_count_{Http::DEFAULT_MAX_HEADERS_COUNT}; absl::optional idle_timeout_; absl::optional max_connection_duration_; + bool http1_safe_max_connection_duration_{false}; absl::optional max_stream_duration_; std::chrono::milliseconds stream_idle_timeout_{}; std::chrono::milliseconds request_timeout_{}; diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index e9094f6bcdf9..d98b1008e2fd 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -5,6 +5,8 @@ #include "test/test_common/logging.h" #include "test/test_common/test_runtime.h" +#include "conn_manager_impl_test_base.h" + using testing::_; using testing::An; using testing::AnyNumber; @@ -22,7 +24,7 @@ namespace Envoy { namespace Http { TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponse) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); // Store the basic request encoder during filter chain setup. std::shared_ptr filter(new NiceMock()); @@ -92,7 +94,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponse) { // Similar to HeaderOnlyRequestAndResponse but uses newStreamHandle and has // lifetime checks. TEST_F(HttpConnectionManagerImplTest, HandleLifetime) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); Http::RequestDecoderHandlePtr decoder_handle; // Store the basic request encoder during filter chain setup. @@ -169,7 +171,7 @@ TEST_F(HttpConnectionManagerImplTest, HandleLifetime) { } TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponseWithEarlyHeaderMutation) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); auto mock_early_header_mutation_1 = std::make_unique>(); auto mock_early_header_mutation_2 = std::make_unique>(); @@ -260,7 +262,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponseWithEarlyHeade TEST_F(HttpConnectionManagerImplTest, 1xxResponse) { proxy_100_continue_ = true; - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); // Store the basic request encoder during filter chain setup. std::shared_ptr filter(new NiceMock()); @@ -318,7 +320,7 @@ TEST_F(HttpConnectionManagerImplTest, 1xxResponse) { TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithEncoderFiltersProxyingDisabled) { proxy_100_continue_ = false; - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -345,7 +347,7 @@ TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithEncoderFiltersProxyingDisab TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithEncoderFilters) { proxy_100_continue_ = true; - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -371,7 +373,7 @@ TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithEncoderFilters) { TEST_F(HttpConnectionManagerImplTest, PauseResume1xx) { proxy_100_continue_ = true; - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -405,7 +407,7 @@ TEST_F(HttpConnectionManagerImplTest, PauseResume1xx) { // Regression test for https://github.com/envoyproxy/envoy/issues/10923. TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithDecoderPause) { proxy_100_continue_ = true; - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); std::shared_ptr filter(new NiceMock()); @@ -472,7 +474,7 @@ TEST_F(HttpConnectionManagerImplTest, 1xxResponseWithDecoderPause) { // When create new stream, the stream info will be populated from the connection. TEST_F(HttpConnectionManagerImplTest, PopulateStreamInfo) { - setup(true, "", false); + setup(SetupOpts().setSsl(true).setTracing(false)); // Set up the codec. Buffer::OwnedImpl fake_input("input"); @@ -496,7 +498,7 @@ TEST_F(HttpConnectionManagerImplTest, PopulateStreamInfo) { // By default, Envoy will set the server header to the server name, here "custom-value" TEST_F(HttpConnectionManagerImplTest, ServerHeaderOverwritten) { - setup(false, "custom-value", false); + setup(SetupOpts().setServerName("custom-value").setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -510,7 +512,7 @@ TEST_F(HttpConnectionManagerImplTest, ServerHeaderOverwritten) { // When configured APPEND_IF_ABSENT if the server header is present it will be retained. TEST_F(HttpConnectionManagerImplTest, ServerHeaderAppendPresent) { server_transformation_ = HttpConnectionManagerProto::APPEND_IF_ABSENT; - setup(false, "custom-value", false); + setup(SetupOpts().setServerName("custom-value").setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -524,7 +526,7 @@ TEST_F(HttpConnectionManagerImplTest, ServerHeaderAppendPresent) { // When configured APPEND_IF_ABSENT if the server header is absent the server name will be set. TEST_F(HttpConnectionManagerImplTest, ServerHeaderAppendAbsent) { server_transformation_ = HttpConnectionManagerProto::APPEND_IF_ABSENT; - setup(false, "custom-value", false); + setup(SetupOpts().setServerName("custom-value").setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -538,7 +540,7 @@ TEST_F(HttpConnectionManagerImplTest, ServerHeaderAppendAbsent) { // When configured PASS_THROUGH, the server name will pass through. TEST_F(HttpConnectionManagerImplTest, ServerHeaderPassthroughPresent) { server_transformation_ = HttpConnectionManagerProto::PASS_THROUGH; - setup(false, "custom-value", false); + setup(SetupOpts().setServerName("custom-value").setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -552,7 +554,7 @@ TEST_F(HttpConnectionManagerImplTest, ServerHeaderPassthroughPresent) { // When configured PASS_THROUGH, the server header will not be added if absent. TEST_F(HttpConnectionManagerImplTest, ServerHeaderPassthroughAbsent) { server_transformation_ = HttpConnectionManagerProto::PASS_THROUGH; - setup(false, "custom-value", false); + setup(SetupOpts().setServerName("custom-value").setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -565,7 +567,7 @@ TEST_F(HttpConnectionManagerImplTest, ServerHeaderPassthroughAbsent) { TEST_F(HttpConnectionManagerImplTest, InvalidPathWithDualFilter) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -604,7 +606,7 @@ TEST_F(HttpConnectionManagerImplTest, InvalidPathWithDualFilter) { // Invalid paths are rejected with 400. TEST_F(HttpConnectionManagerImplTest, PathFailedtoSanitize) { - setup(false, ""); + setup(); // Enable path sanitizer normalize_path_ = true; @@ -652,7 +654,7 @@ TEST_F(HttpConnectionManagerImplTest, PathFailedtoSanitize) { // Filters observe normalized paths, not the original path, when path // normalization is configured. TEST_F(HttpConnectionManagerImplTest, FilterShouldUseSantizedPath) { - setup(false, ""); + setup(); // Enable path sanitizer normalize_path_ = true; const std::string original_path = "/x/%2E%2e/z"; @@ -699,7 +701,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterShouldUseSantizedPath) { // The router observes normalized paths, not the original path, when path // normalization is configured. TEST_F(HttpConnectionManagerImplTest, RouteShouldUseSantizedPath) { - setup(false, ""); + setup(); // Enable path sanitizer normalize_path_ = true; const std::string original_path = "/x/%2E%2e/z"; @@ -795,7 +797,7 @@ TEST_F(HttpConnectionManagerImplTest, EscapedSlashesRedirectedAfterOtherNormaliz } TEST_F(HttpConnectionManagerImplTest, AllNormalizationsWithEscapedSlashesForwarded) { - setup(false, ""); + setup(); // Enable path sanitizer normalize_path_ = true; merge_slashes_ = true; @@ -844,7 +846,7 @@ TEST_F(HttpConnectionManagerImplTest, AllNormalizationsWithEscapedSlashesForward } TEST_F(HttpConnectionManagerImplTest, RouteOverride) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -1045,7 +1047,7 @@ TEST_F(HttpConnectionManagerImplTest, RouteOverride) { // original route returned by route config (upstream cluster default), when the setRoute filter // callback is applied. TEST_F(HttpConnectionManagerImplTest, FilterSetRouteToDelegatingRouteWithClusterOverride) { - setup(false, ""); + setup(); setupFilterChain(2, 0); // Cluster mocks: default and foo @@ -1131,7 +1133,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterSetRouteToDelegatingRouteWithCluster // Test that all methods supported by DelegatingRouteEntry delegate correctly TEST_F(HttpConnectionManagerImplTest, DelegatingRouteEntryAllCalls) { - setup(false, ""); + setup(); setupFilterChain(2, 0); // Cluster mock: foo @@ -1326,7 +1328,7 @@ TEST_F(HttpConnectionManagerImplTest, DelegatingRouteEntryAllCalls) { // Filters observe host header w/o port's part when port's removal is configured TEST_F(HttpConnectionManagerImplTest, FilterShouldUseNormalizedHost) { - setup(false, ""); + setup(); // Enable port removal strip_port_type_ = Http::StripPortType::MatchingHost; const std::string original_host = "host:443"; @@ -1371,7 +1373,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterShouldUseNormalizedHost) { // The router observes host header w/o port, not the original host, when // remove_port is configured TEST_F(HttpConnectionManagerImplTest, RouteShouldUseNormalizedHost) { - setup(false, ""); + setup(); // Enable port removal strip_port_type_ = Http::StripPortType::MatchingHost; const std::string original_host = "host:443"; @@ -1411,7 +1413,7 @@ TEST_F(HttpConnectionManagerImplTest, RouteShouldUseNormalizedHost) { // Observe that we strip the trailing dot. TEST_F(HttpConnectionManagerImplTest, StripTrailingHostDot) { - setup(false, ""); + setup(); // Enable removal of host's trailing dot. strip_trailing_host_dot_ = true; const std::string original_host = "host."; @@ -1431,7 +1433,7 @@ TEST_F(HttpConnectionManagerImplTest, StripTrailingHostDot) { } TEST_F(HttpConnectionManagerImplTest, HostWithoutTrailingDot) { - setup(false, ""); + setup(); // Enable removal of host's trailing dot. strip_trailing_host_dot_ = true; const std::string original_host = "host"; @@ -1451,7 +1453,7 @@ TEST_F(HttpConnectionManagerImplTest, HostWithoutTrailingDot) { } TEST_F(HttpConnectionManagerImplTest, DateHeaderNotPresent) { - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); const auto* modified_headers = sendResponseHeaders( @@ -1462,7 +1464,7 @@ TEST_F(HttpConnectionManagerImplTest, DateHeaderNotPresent) { } TEST_F(HttpConnectionManagerImplTest, DateHeaderPresent) { - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); const std::string expected_date{"Tue, 15 Nov 1994 08:12:31 GMT"}; @@ -1476,7 +1478,7 @@ TEST_F(HttpConnectionManagerImplTest, DateHeaderPresent) { } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlow) { - setup(false, ""); + setup(); auto* span = new NiceMock(); EXPECT_CALL(*tracer_, startSpan_(_, _, _, _)) @@ -1636,7 +1638,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlow) { } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorator) { - setup(false, ""); + setup(); auto* span = new NiceMock(); EXPECT_CALL(*tracer_, startSpan_(_, _, _, _)) @@ -1704,7 +1706,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorat } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecoratorPropagateFalse) { - setup(false, ""); + setup(); auto* span = new NiceMock(); EXPECT_CALL(*tracer_, startSpan_(_, _, _, _)) @@ -1773,7 +1775,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorat } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecoratorOverrideOp) { - setup(false, ""); + setup(); auto* span = new NiceMock(); EXPECT_CALL(*tracer_, startSpan_(_, _, _, _)) @@ -1843,7 +1845,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowIngressDecorat } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorator) { - setup(false, ""); + setup(); envoy::type::v3::FractionalPercent percent1; percent1.set_numerator(100); envoy::type::v3::FractionalPercent percent2; @@ -1927,7 +1929,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorato } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecoratorPropagateFalse) { - setup(false, ""); + setup(); envoy::type::v3::FractionalPercent percent1; percent1.set_numerator(100); envoy::type::v3::FractionalPercent percent2; @@ -2013,7 +2015,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorato } TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecoratorOverrideOp) { - setup(false, ""); + setup(); envoy::type::v3::FractionalPercent percent1; percent1.set_numerator(100); envoy::type::v3::FractionalPercent percent2; @@ -2091,7 +2093,7 @@ TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecorato TEST_F(HttpConnectionManagerImplTest, StartAndFinishSpanNormalFlowEgressDecoratorOverrideOpNoActiveSpan) { - setup(false, ""); + setup(); envoy::type::v3::FractionalPercent percent1; percent1.set_numerator(100); envoy::type::v3::FractionalPercent percent2; @@ -2148,7 +2150,7 @@ TEST_F(HttpConnectionManagerImplTest, } TEST_F(HttpConnectionManagerImplTest, NoHCMTracingConfigAndActiveSpanWouldBeNullSpan) { - setup(false, ""); + setup(); // Null HCM tracing config. tracing_config_ = nullptr; @@ -2206,7 +2208,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLog) { // stream_info.downstreamRemoteAddress will infer the address from request // headers instead of the physical connection use_remote_address_ = false; - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2264,7 +2266,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLog) { } TEST_F(HttpConnectionManagerImplTest, TestFilterCanEnrichAccessLogs) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2316,7 +2318,7 @@ TEST_F(HttpConnectionManagerImplTest, TestFilterCanEnrichAccessLogs) { } TEST_F(HttpConnectionManagerImplTest, TestRemoteDownstreamDisconnectAccessLog) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2360,7 +2362,7 @@ TEST_F(HttpConnectionManagerImplTest, TestRemoteDownstreamDisconnectAccessLog) { } TEST_F(HttpConnectionManagerImplTest, TestLocalDownstreamDisconnectAccessLog) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2402,7 +2404,7 @@ TEST_F(HttpConnectionManagerImplTest, TestLocalDownstreamDisconnectAccessLog) { } TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithTrailers) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2455,7 +2457,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithTrailers) { } TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithInvalidRequest) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2501,7 +2503,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithInvalidRequest) { } TEST_F(HttpConnectionManagerImplTest, TestAccessLogOnNewRequest) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2563,7 +2565,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogOnNewRequest) { } TEST_F(HttpConnectionManagerImplTest, TestAccessLogOnTunnelEstablished) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2627,7 +2629,8 @@ TEST_F(HttpConnectionManagerImplTest, TestPeriodicAccessLogging) { request_timeout_ = std::chrono::milliseconds(0); request_headers_timeout_ = std::chrono::milliseconds(0); max_stream_duration_ = std::nullopt; - setup(false, "server_name"); + + setup(SetupOpts().setServerName("server-opts")); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2708,7 +2711,7 @@ class StreamErrorOnInvalidHttpMessageTest : public HttpConnectionManagerImplTest public: void sendInvalidRequestAndVerifyConnectionState(bool stream_error_on_invalid_http_message, bool send_complete_request = true) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)) .WillRepeatedly(Invoke([&](Buffer::Instance& data) -> Http::Status { @@ -2786,7 +2789,7 @@ TEST_F(StreamErrorOnInvalidHttpMessageTest, ConnectionOpenIfCodecStreamErrorIsTr } TEST_F(HttpConnectionManagerImplTest, TestAccessLogSsl) { - setup(true, ""); + setup(SetupOpts().setSsl(true)); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -2840,7 +2843,7 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogSsl) { } TEST_F(HttpConnectionManagerImplTest, DoNotStartSpanIfTracingIsNotEnabled) { - setup(false, ""); + setup(); // Disable tracing. tracing_config_.reset(); @@ -2883,7 +2886,7 @@ TEST_F(HttpConnectionManagerImplTest, DoNotStartSpanIfTracingIsNotEnabled) { } TEST_F(HttpConnectionManagerImplTest, NoPath) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -2907,7 +2910,7 @@ TEST_F(HttpConnectionManagerImplTest, NoPath) { // per-route level. The connection manager config is responsible for managing // the default configuration aspects. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutNotConfigured) { - setup(false, ""); + setup(); EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, createTimer_(_)).Times(0); EXPECT_CALL(*codec_, dispatch(_)) @@ -2933,7 +2936,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutNotConfigured) { // headers, if it fires we don't faceplant. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutGlobal) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillRepeatedly(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* idle_timer = setUpTimer(); @@ -2965,7 +2968,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutGlobal) { TEST_F(HttpConnectionManagerImplTest, AccessEncoderRouteBeforeHeadersArriveOnIdleTimeout) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); @@ -3017,7 +3020,7 @@ TEST_F(HttpConnectionManagerImplTest, AccessEncoderRouteBeforeHeadersArriveOnIdl TEST_F(HttpConnectionManagerImplTest, TestStreamIdleAccessLog) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillRepeatedly(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* idle_timer = setUpTimer(); @@ -3072,7 +3075,7 @@ TEST_F(HttpConnectionManagerImplTest, TestStreamIdleAccessLog) { // Test timeout variants. TEST_F(HttpConnectionManagerImplTest, DurationTimeout) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); setupFilterChain(1, 0); RequestHeaderMap* latched_headers = nullptr; @@ -3272,7 +3275,7 @@ TEST_F(HttpConnectionManagerImplTest, DurationTimeout) { // Per-route timeouts override the global stream idle timeout. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutRouteOverride) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(30))); @@ -3302,7 +3305,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutRouteOverride) { // Per-route zero timeout overrides the global stream idle timeout. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutRouteZeroOverride) { stream_idle_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(0))); @@ -3331,7 +3334,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutRouteZeroOverride) { // Validate the per-stream idle timeout after having sent downstream headers. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterDownstreamHeaders) { - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(10))); @@ -3372,7 +3375,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterDownstreamHeaders // Validate the per-stream idle timer is properly disabled when the stream terminates normally. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutNormalTermination) { - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(10))); @@ -3402,7 +3405,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutNormalTermination) { // Validate the per-stream idle timeout after having sent downstream // headers+body. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterDownstreamHeadersAndBody) { - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(10))); @@ -3446,7 +3449,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterDownstreamHeaders // Validate the per-stream idle timeout after upstream headers have been sent. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterUpstreamHeaders) { - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(10))); @@ -3497,7 +3500,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterUpstreamHeaders) // Validate the per-stream idle timeout after a sequence of header/data events. TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterBidiData) { - setup(false, ""); + setup(); ON_CALL(route_config_provider_.route_config_->route_->route_entry_, idleTimeout()) .WillByDefault(Return(std::chrono::milliseconds(10))); proxy_100_continue_ = true; @@ -3571,7 +3574,7 @@ TEST_F(HttpConnectionManagerImplTest, PerStreamIdleTimeoutAfterBidiData) { } TEST_F(HttpConnectionManagerImplTest, RequestTimeoutDisabledByDefault) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, createTimer_).Times(0); @@ -3588,7 +3591,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutDisabledByDefault) { TEST_F(HttpConnectionManagerImplTest, RequestTimeoutDisabledIfSetToZero) { request_timeout_ = std::chrono::milliseconds(0); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, createTimer_).Times(0); @@ -3603,7 +3606,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutDisabledIfSetToZero) { TEST_F(HttpConnectionManagerImplTest, RequestTimeoutValidlyConfigured) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* request_timer = setUpTimer(); @@ -3623,7 +3626,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutValidlyConfigured) { TEST_F(HttpConnectionManagerImplTest, RequestTimeoutCallbackDisarmsAndReturns408) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); std::string response_body; EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -3653,7 +3656,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutCallbackDisarmsAndReturns408 TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsNotDisarmedOnIncompleteRequestWithHeader) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* request_timer = setUpTimer(); @@ -3680,7 +3683,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsNotDisarmedOnIncompleteReq TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestWithHeader) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* request_timer = setUpTimer(); @@ -3706,7 +3709,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestW TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestWithData) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { Event::MockTimer* request_timer = setUpTimer(); @@ -3733,7 +3736,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestW TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestWithTrailers) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { Event::MockTimer* request_timer = setUpTimer(); @@ -3762,7 +3765,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnCompleteRequestW TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnEncodeHeaders) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { @@ -3799,7 +3802,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnEncodeHeaders) { TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnConnectionTermination) { request_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* request_timer = setUpTimer(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -3825,7 +3828,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestTimeoutIsDisarmedOnConnectionTermin TEST_F(HttpConnectionManagerImplTest, RequestHeaderTimeoutDisarmedAfterHeaders) { request_headers_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* request_header_timer; EXPECT_CALL(*codec_, dispatch(_)) @@ -3863,7 +3866,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestHeaderTimeoutDisarmedAfterHeaders) TEST_F(HttpConnectionManagerImplTest, RequestHeaderTimeoutCallbackDisarmsAndReturns408) { request_headers_timeout_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* request_header_timer; EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -3888,7 +3891,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestHeaderTimeoutCallbackDisarmsAndRetu TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationDisabledIfSetToZero) { max_stream_duration_ = std::chrono::milliseconds(0); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { EXPECT_CALL(filter_callbacks_.connection_.dispatcher_, createTimer_).Times(0); @@ -3903,7 +3906,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationDisabledIfSetToZero) { TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationValidlyConfigured) { max_stream_duration_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { Event::MockTimer* duration_timer = setUpTimer(); @@ -3921,7 +3924,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationValidlyConfigured) { TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationCallbackResetStream) { max_stream_duration_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* duration_timer = setUpTimer(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -3944,7 +3947,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationCallbackResetStream) { TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationFiredReturn408IfRequestWasNotComplete) { max_stream_duration_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* duration_timer = setUpTimer(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { @@ -3974,7 +3977,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationFiredReturn408IfRequestWa TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationFiredReturn504IfRequestWasFullyRead) { max_stream_duration_ = std::chrono::milliseconds(10); - setup(false, ""); + setup(); Event::MockTimer* duration_timer = setUpTimer(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { @@ -4003,7 +4006,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationFiredReturn504IfRequestWa TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationCallbackNotCalledIfResetStreamValidly) { max_stream_duration_ = std::chrono::milliseconds(5000); - setup(false, ""); + setup(); Event::MockTimer* duration_timer = setUpTimer(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -4023,7 +4026,7 @@ TEST_F(HttpConnectionManagerImplTest, MaxStreamDurationCallbackNotCalledIfResetS } TEST_F(HttpConnectionManagerImplTest, RejectWebSocketOnNonWebSocketRoute) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); RequestHeaderMapPtr headers{new TestRequestHeaderMapImpl{{":authority", "host"}, @@ -4054,7 +4057,7 @@ TEST_F(HttpConnectionManagerImplTest, RejectWebSocketOnNonWebSocketRoute) { // Make sure for upgrades, we do not append Connection: Close when draining. TEST_F(HttpConnectionManagerImplTest, FooUpgradeDrainClose) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); // Store the basic request encoder during filter chain setup. auto* filter = new MockStreamFilter(); @@ -4120,7 +4123,7 @@ TEST_F(HttpConnectionManagerImplTest, FooUpgradeDrainClose) { // Make sure CONNECT requests hit the upgrade filter path. TEST_F(HttpConnectionManagerImplTest, ConnectAsUpgrade) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); EXPECT_CALL(filter_factory_, createUpgradeFilterChain("CONNECT", _, _, _)) .WillRepeatedly(Return(true)); @@ -4144,7 +4147,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectAsUpgrade) { } TEST_F(HttpConnectionManagerImplTest, ConnectWithEmptyPath) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); EXPECT_CALL(filter_factory_, createUpgradeFilterChain("CONNECT", _, _, _)) .WillRepeatedly(Return(true)); @@ -4170,7 +4173,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectWithEmptyPath) { // Regression test for https://github.com/envoyproxy/envoy/issues/10138 TEST_F(HttpConnectionManagerImplTest, DrainCloseRaceWithClose) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -4215,7 +4218,7 @@ TEST_F(HttpConnectionManagerImplTest, DrainCloseRaceWithClose) { TEST_F(HttpConnectionManagerImplTest, FilterThatWaitsForBodyCanBeCalledAfterFilterThatAddsBodyEvenIfItIsNotLast) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -4263,7 +4266,7 @@ TEST_F(HttpConnectionManagerImplTest, } TEST_F(HttpConnectionManagerImplTest, DrainClose) { - setup(true, ""); + setup(SetupOpts().setSsl(true)); MockStreamDecoderFilter* filter = new NiceMock(); EXPECT_CALL(filter_factory_, createFilterChain(_)) @@ -4319,7 +4322,7 @@ TEST_F(HttpConnectionManagerImplTest, DrainClose) { class ProxyStatusTest : public HttpConnectionManagerImplTest { public: void initialize() { - setup(/*ssl=*/false, servername_, /*tracing=*/false); + setup(SetupOpts().setServerName(servername_).setTracing(false)); setUpEncoderAndDecoder(/*request_with_data_and_trailers=*/false, /*decode_headers_stop_all=*/false); sendRequestHeadersAndData(); diff --git a/test/common/http/conn_manager_impl_test_2.cc b/test/common/http/conn_manager_impl_test_2.cc index e829a42e42ab..8a37e53703ca 100644 --- a/test/common/http/conn_manager_impl_test_2.cc +++ b/test/common/http/conn_manager_impl_test_2.cc @@ -20,7 +20,7 @@ namespace Envoy { namespace Http { TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete) { - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, false)) @@ -44,7 +44,7 @@ TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete) { TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete10) { EXPECT_CALL(*codec_, protocol()).WillRepeatedly(Return(Protocol::Http10)); - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, false)) @@ -69,7 +69,7 @@ TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete10) { TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete10NoOptimize) { EXPECT_CALL(runtime_.snapshot_, getBoolean(_, _)).WillRepeatedly(Return(false)); EXPECT_CALL(*codec_, protocol()).WillRepeatedly(Return(Protocol::Http10)); - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, false)) @@ -94,7 +94,7 @@ TEST_F(HttpConnectionManagerImplTest, ResponseBeforeRequestComplete10NoOptimize) } TEST_F(HttpConnectionManagerImplTest, DisconnectOnProxyConnectionDisconnect) { - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); @@ -120,7 +120,7 @@ TEST_F(HttpConnectionManagerImplTest, DisconnectOnProxyConnectionDisconnect) { } TEST_F(HttpConnectionManagerImplTest, ResponseStartBeforeRequestComplete) { - setup(false, ""); + setup(SetupOpts().setServerName("")); // This is like ResponseBeforeRequestComplete, but it tests the case where we start the reply // before the request completes, but don't finish the reply until after the request completes. @@ -181,7 +181,7 @@ TEST_F(HttpConnectionManagerImplTest, ResponseStartBeforeRequestComplete) { TEST_F(HttpConnectionManagerImplTest, DownstreamDisconnect) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { conn_manager_->newStream(response_encoder_); @@ -201,7 +201,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamDisconnect) { TEST_F(HttpConnectionManagerImplTest, DownstreamProtocolError) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { conn_manager_->newStream(response_encoder_); @@ -225,7 +225,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamProtocolError) { TEST_F(HttpConnectionManagerImplTest, TestDownstreamProtocolErrorAccessLog) { std::shared_ptr handler(new NiceMock()); access_logs_ = {handler}; - setup(false, ""); + setup(); EXPECT_CALL(*handler, log(_, _)) .WillOnce(Invoke( @@ -246,7 +246,7 @@ TEST_F(HttpConnectionManagerImplTest, TestDownstreamProtocolErrorAccessLog) { } TEST_F(HttpConnectionManagerImplTest, TestDownstreamProtocolErrorAfterHeadersAccessLog) { - setup(false, ""); + setup(); std::shared_ptr filter(new NiceMock()); std::shared_ptr handler(new NiceMock()); @@ -289,7 +289,7 @@ TEST_F(HttpConnectionManagerImplTest, FrameFloodError) { std::shared_ptr log_handler = std::make_shared>(); access_logs_ = {log_handler}; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { conn_manager_->newStream(response_encoder_); @@ -323,7 +323,7 @@ TEST_F(HttpConnectionManagerImplTest, EnvoyOverloadError) { std::shared_ptr log_handler = std::make_shared>(); access_logs_ = {log_handler}; - setup(false, ""); + setup(); ASSERT_EQ(0U, stats_.named_.downstream_rq_overload_close_.value()); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -360,7 +360,7 @@ TEST_F(HttpConnectionManagerImplTest, IdleTimeoutNoCodec) { idle_timeout_ = (std::chrono::milliseconds(10)); Event::MockTimer* idle_timer = setUpTimer(); EXPECT_CALL(*idle_timer, enableTimer(_, _)); - setup(false, ""); + setup(); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite, _)); EXPECT_CALL(*idle_timer, disableTimer()); @@ -373,7 +373,7 @@ TEST_F(HttpConnectionManagerImplTest, IdleTimeout) { idle_timeout_ = (std::chrono::milliseconds(10)); Event::MockTimer* idle_timer = setUpTimer(); EXPECT_CALL(*idle_timer, enableTimer(_, _)); - setup(false, ""); + setup(); MockStreamDecoderFilter* filter = new NiceMock(); EXPECT_CALL(filter_factory_, createFilterChain(_)) @@ -418,7 +418,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionDurationResponseFlag) { max_connection_duration_ = (std::chrono::milliseconds(10)); Event::MockTimer* connection_duration_timer = setUpTimer(); EXPECT_CALL(*connection_duration_timer, enableTimer(_, _)); - setup(false, ""); + setup(); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite, _)); filter_callbacks_.connection_.streamInfo().setResponseFlag( @@ -440,7 +440,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionDurationNoCodec) { max_connection_duration_ = (std::chrono::milliseconds(10)); Event::MockTimer* connection_duration_timer = setUpTimer(); EXPECT_CALL(*connection_duration_timer, enableTimer(_, _)); - setup(false, ""); + setup(); EXPECT_CALL(filter_callbacks_.connection_, close(Network::ConnectionCloseType::FlushWrite, _)); EXPECT_CALL(*connection_duration_timer, disableTimer()); @@ -454,7 +454,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionDurationNoCodec) { TEST_F(HttpConnectionManagerImplTest, MaxRequests) { max_requests_per_connection_ = 1; codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); Event::MockTimer* drain_timer = setUpTimer(); EXPECT_CALL(*drain_timer, enableTimer(_, _)); @@ -479,11 +479,63 @@ TEST_F(HttpConnectionManagerImplTest, MaxRequests) { conn_manager_->onEvent(Network::ConnectionEvent::RemoteClose); } +// max_requests_per_connection is met first then the drain timer fires. Drain timer should be +// ignored. +TEST_F(HttpConnectionManagerImplTest, DrainConnectionUponCompletionVsOnDrainTimeoutHttp11) { + // Http1.1 is used for this test because it defaults to keeping the connection alive. + EXPECT_CALL(*codec_, protocol()).WillRepeatedly(Return(Protocol::Http11)); + max_requests_per_connection_ = 2; + max_connection_duration_ = std::chrono::milliseconds(10); + + Event::MockTimer* connection_duration_timer = setUpTimer(); + EXPECT_CALL(*connection_duration_timer, enableTimer(_, _)); + // Set up connection. + setup(); + + // Create a filter so we can encode responses. + MockStreamDecoderFilter* filter = new NiceMock(); + EXPECT_CALL(filter_factory_, createFilterChain(_)) + .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { + auto factory = createDecoderFilterFactoryCb(StreamDecoderFilterSharedPtr{filter}); + manager.applyFilterFactoryCb({}, factory); + return true; + })); + + startRequest(true); + // Encode response, connection will not be closed since we're using http 1.1. + filter->callbacks_->streamInfo().setResponseCodeDetails(""); + filter->callbacks_->encodeHeaders( + ResponseHeaderMapPtr{new TestResponseHeaderMapImpl{{":status", "200"}}}, true, "details"); + response_encoder_.stream_.codec_callbacks_->onCodecEncodeComplete(); + + // Now connection is established and codec is not nullptr. This should start the drain timer. + Event::MockTimer* drain_timer = setUpTimer(); + EXPECT_CALL(*drain_timer, enableTimer(_, _)); + connection_duration_timer->invokeCallback(); + EXPECT_EQ(1U, stats_.named_.downstream_cx_max_duration_reached_.value()); + + // Get a fresh mock filter. + filter = new NiceMock(); + // Send a second request. This will cause max_requests_per_connection limit to be reached. + // Connection drain state will be set to closing. + startRequest(true); + EXPECT_EQ(1U, stats_.named_.downstream_cx_max_requests_reached_.value()); + + drain_timer->invokeCallback(); + + // Send the last response. The drain timer having already fired should not be an issue. + EXPECT_CALL(response_encoder_, encodeHeaders(_, true)); + filter->callbacks_->streamInfo().setResponseCodeDetails(""); + filter->callbacks_->encodeHeaders( + ResponseHeaderMapPtr{new TestResponseHeaderMapImpl{{":status", "200"}}}, true, "details"); + response_encoder_.stream_.codec_callbacks_->onCodecEncodeComplete(); +} + TEST_F(HttpConnectionManagerImplTest, ConnectionDuration) { max_connection_duration_ = (std::chrono::milliseconds(10)); Event::MockTimer* connection_duration_timer = setUpTimer(); EXPECT_CALL(*connection_duration_timer, enableTimer(_, _)); - setup(false, ""); + setup(); MockStreamDecoderFilter* filter = new NiceMock(); EXPECT_CALL(filter_factory_, createFilterChain(_)) @@ -520,8 +572,51 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionDuration) { EXPECT_EQ(1U, stats_.named_.downstream_cx_max_duration_reached_.value()); } +TEST_F(HttpConnectionManagerImplTest, ConnectionDurationSafeHttp1) { + EXPECT_CALL(*codec_, protocol()).WillRepeatedly(Return(Protocol::Http10)); + max_connection_duration_ = std::chrono::milliseconds(10); + Event::MockTimer* connection_duration_timer = setUpTimer(); + EXPECT_CALL(*connection_duration_timer, enableTimer(_, _)); + setup(SetupOpts().setHttp1SafeMaxConnectionDuration(true)); + + MockStreamDecoderFilter* filter = new NiceMock(); + EXPECT_CALL(filter_factory_, createFilterChain(_)) + .WillOnce(Invoke([&](FilterChainManager& manager) -> bool { + auto factory = createDecoderFilterFactoryCb(StreamDecoderFilterSharedPtr{filter}); + manager.applyFilterFactoryCb({}, factory); + return true; + })); + + EXPECT_CALL(*filter, decodeHeaders(_, false)) + .WillOnce(Return(FilterHeadersStatus::StopIteration)); + EXPECT_CALL(*filter, decodeData(_, true)) + .WillOnce(Return(FilterDataStatus::StopIterationNoBuffer)); + startRequest(true, "hello"); + + EXPECT_CALL(*connection_duration_timer, disableTimer()); + connection_duration_timer->invokeCallback(); + EXPECT_EQ(1U, stats_.named_.downstream_cx_http1_soft_drain_.value()); + EXPECT_EQ(1U, stats_.named_.downstream_cx_max_duration_reached_.value()); + + // Connection manager now waits to send another response, adds the Connection:close header to it, + // then closes the connection. + EXPECT_CALL(response_encoder_, encodeHeaders(_, _)) + .WillOnce(Invoke([&](const ResponseHeaderMap& headers, bool) { + // Check that the connection:close header is present. + ASSERT_NE(headers.Connection(), nullptr); + EXPECT_EQ(headers.getConnectionValue(), Headers::get().ConnectionValues.Close); + response_encoder_.stream_.codec_callbacks_->onCodecEncodeComplete(); + })); + // Expect stream & connection to close after response is sent. + expectOnDestroy(); + + ResponseHeaderMapPtr response_headers{new TestResponseHeaderMapImpl{{":status", "200"}}}; + filter->callbacks_->streamInfo().setResponseCodeDetails(""); + filter->callbacks_->encodeHeaders(std::move(response_headers), true, "details"); +} + TEST_F(HttpConnectionManagerImplTest, IntermediateBufferingEarlyResponse) { - setup(false, ""); + setup(); setupFilterChain(2, 0); @@ -554,7 +649,7 @@ TEST_F(HttpConnectionManagerImplTest, IntermediateBufferingEarlyResponse) { } TEST_F(HttpConnectionManagerImplTest, DoubleBuffering) { - setup(false, ""); + setup(); setupFilterChain(3, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, false)) @@ -589,7 +684,7 @@ TEST_F(HttpConnectionManagerImplTest, DoubleBuffering) { } TEST_F(HttpConnectionManagerImplTest, ZeroByteDataFiltering) { - setup(false, ""); + setup(); setupFilterChain(2, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, false)) @@ -621,7 +716,7 @@ TEST_F(HttpConnectionManagerImplTest, ZeroByteDataFiltering) { TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInTrailersCallback) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -708,7 +803,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInTrailersCallback) { } TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInDataCallbackNoTrailers) { - setup(false, ""); + setup(); setupFilterChain(2, 2); std::string trailers_data("trailers"); @@ -788,7 +883,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddTrailersInDataCallbackNoTrailers) TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -871,7 +966,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback) { // Don't send data frames, only headers and trailers. TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback_NoDataFrames) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -932,7 +1027,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback_NoDataFram // Don't send data frames, only headers and trailers. TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback_ContinueAfterCallback) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -999,7 +1094,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInTrailersCallback_ContinueAf // Add*Data during the *Data callbacks. TEST_F(HttpConnectionManagerImplTest, FilterAddBodyDuringDecodeData) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -1068,7 +1163,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyDuringDecodeData) { } TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInline) { - setup(false, ""); + setup(); setupFilterChain(2, 2); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -1110,7 +1205,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyInline) { } TEST_F(HttpConnectionManagerImplTest, BlockRouteCacheTest) { - setup(false, ""); + setup(); MockStreamDecoderFilter* filter = new NiceMock(); EXPECT_CALL(filter_factory_, createFilterChain(_)) @@ -1183,7 +1278,7 @@ TEST_F(HttpConnectionManagerImplTest, BlockRouteCacheTest) { } TEST_F(HttpConnectionManagerImplTest, Filter) { - setup(false, ""); + setup(); setupFilterChain(3, 2); const std::string fake_cluster1_name = "fake_cluster1"; @@ -1244,7 +1339,7 @@ TEST_F(HttpConnectionManagerImplTest, Filter) { // the line. Also tests that setRoute(nullptr) is equivalent to attempting route resolution and // failing to find a route. TEST_F(HttpConnectionManagerImplTest, FilterSetRouteToNullPtr) { - setup(false, ""); + setup(); setupFilterChain(2, 1); const std::string fake_cluster1_name = "fake_cluster1"; @@ -1288,7 +1383,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterSetRouteToNullPtr) { } TEST_F(HttpConnectionManagerImplTest, UpstreamWatermarkCallbacks) { - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -1327,7 +1422,7 @@ TEST_F(HttpConnectionManagerImplTest, UpstreamWatermarkCallbacks) { } TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksPassedOnWithLazyCreation) { - setup(false, ""); + setup(); // Make sure codec_ is created. EXPECT_CALL(*codec_, dispatch(_)); @@ -1389,7 +1484,7 @@ TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksPassedOnWith } TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksUnwoundWithLazyCreation) { - setup(false, ""); + setup(); // Make sure codec_ is created. EXPECT_CALL(*codec_, dispatch(_)); @@ -1454,7 +1549,7 @@ TEST_F(HttpConnectionManagerImplTest, UnderlyingConnectionWatermarksUnwoundWithL TEST_F(HttpConnectionManagerImplTest, AlterFilterWatermarkLimits) { initial_buffer_limit_ = 100; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -1487,7 +1582,7 @@ TEST_F(HttpConnectionManagerImplTest, HitFilterWatermarkLimits) { initial_buffer_limit_ = 1; streaming_filter_ = true; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); // The filter is a streaming filter. Sending 4 bytes should hit the @@ -1547,7 +1642,7 @@ TEST_F(HttpConnectionManagerImplTest, HitFilterWatermarkLimits) { TEST_F(HttpConnectionManagerImplTest, HitRequestBufferLimits) { initial_buffer_limit_ = 10; streaming_filter_ = false; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -1572,7 +1667,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamConnectionTermination) { std::shared_ptr handler(new NiceMock()); access_logs_ = {handler}; - setup(false, ""); + setup(); EXPECT_CALL(*handler, log(_, _)) .WillOnce(Invoke( [](const Formatter::HttpFormatterContext&, const StreamInfo::StreamInfo& stream_info) { @@ -1598,7 +1693,7 @@ TEST_F(HttpConnectionManagerImplTest, HitRequestBufferLimitsIntermediateFilter) { InSequence s; initial_buffer_limit_ = 10; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -1642,7 +1737,7 @@ TEST_F(HttpConnectionManagerImplTest, HitRequestBufferLimitsIntermediateFilter) TEST_F(HttpConnectionManagerImplTest, HitResponseBufferLimitsBeforeHeaders) { initial_buffer_limit_ = 10; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -1683,7 +1778,7 @@ TEST_F(HttpConnectionManagerImplTest, HitResponseBufferLimitsBeforeHeaders) { TEST_F(HttpConnectionManagerImplTest, HitResponseBufferLimitsAfterHeaders) { initial_buffer_limit_ = 10; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -1720,7 +1815,7 @@ TEST_F(HttpConnectionManagerImplTest, HitResponseBufferLimitsAfterHeaders) { TEST_F(HttpConnectionManagerImplTest, FilterHeadReply) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -1763,7 +1858,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterHeadReply) { // up resetting the stream in the doEndStream() path (e.g., via filter reset due to timeout, etc.), // we emit a reset to the codec. TEST_F(HttpConnectionManagerImplTest, ResetWithStoppedFilter) { - setup(false, ""); + setup(); setupFilterChain(1, 1); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -1802,7 +1897,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamRemoteResetConnectError) { std::shared_ptr handler(new NiceMock()); access_logs_ = {handler}; - setup(false, ""); + setup(); codec_->protocol_ = Protocol::Http2; EXPECT_CALL(*handler, log(_, _)) .WillOnce(Invoke( @@ -1831,7 +1926,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamRemoteReset) { std::shared_ptr handler(new NiceMock()); access_logs_ = {handler}; - setup(false, ""); + setup(); codec_->protocol_ = Protocol::Http2; EXPECT_CALL(*handler, log(_, _)) .WillOnce(Invoke( @@ -1860,7 +1955,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamRemoteResetRefused) { std::shared_ptr handler(new NiceMock()); access_logs_ = {handler}; - setup(false, ""); + setup(); codec_->protocol_ = Protocol::Http2; EXPECT_CALL(*handler, log(_, _)) .WillOnce(Invoke( @@ -1885,7 +1980,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamRemoteResetRefused) { // Filter stops headers iteration without ending the stream, then injects a body later. TEST_F(HttpConnectionManagerImplTest, FilterStopIterationInjectBody) { - setup(false, ""); + setup(); setupFilterChain(2, 2); // Decode filter 0 changes end_stream to false. @@ -1931,7 +2026,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterStopIterationInjectBody) { // Filter continues headers iteration without ending the stream, then injects a body later. TEST_F(HttpConnectionManagerImplTest, FilterContinueDontEndStreamInjectBody) { - setup(false, ""); + setup(); setupFilterChain(2, 2); // Decode filter 0 changes end_stream to false. @@ -1976,7 +2071,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterContinueDontEndStreamInjectBody) { } TEST_F(HttpConnectionManagerImplTest, FilterAddBodyContinuation) { - setup(false, ""); + setup(); setupFilterChain(2, 2); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -2052,7 +2147,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterAddBodyContinuation) { // filter1->encodeData(, true) is NOT called. // TEST_F(HttpConnectionManagerImplTest, AddDataWithAllContinue) { - setup(false, ""); + setup(); setupFilterChain(3, 3); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -2145,7 +2240,7 @@ TEST_F(HttpConnectionManagerImplTest, AddDataWithAllContinue) { // filter1->encodeData(, true) is NOT called. // TEST_F(HttpConnectionManagerImplTest, AddDataWithStopAndContinue) { - setup(false, ""); + setup(); setupFilterChain(3, 3); @@ -2212,7 +2307,7 @@ TEST_F(HttpConnectionManagerImplTest, AddDataWithStopAndContinue) { // Use filter direct decode/encodeData() calls without trailers. TEST_F(HttpConnectionManagerImplTest, FilterDirectDecodeEncodeDataNoTrailers) { - setup(false, ""); + setup(); EXPECT_CALL(*route_config_provider_.route_config_, route(_, _, _, _)); setupFilterChain(2, 2); @@ -2281,7 +2376,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterDirectDecodeEncodeDataNoTrailers) { // Use filter direct decode/encodeData() calls with trailers. TEST_F(HttpConnectionManagerImplTest, FilterDirectDecodeEncodeDataTrailers) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -2377,7 +2472,7 @@ TEST_F(HttpConnectionManagerImplTest, FilterDirectDecodeEncodeDataTrailers) { TEST_F(HttpConnectionManagerImplTest, MultipleFilters) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -2492,7 +2587,7 @@ TEST_F(HttpConnectionManagerImplTest, NoNewStreamWhenOverloaded) { getState(Server::OverloadActionNames::get().StopAcceptingRequests)) .WillByDefault(ReturnRef(stop_accepting_requests)); - setup(false, ""); + setup(); EXPECT_CALL(random_, random()) .WillRepeatedly(Return(static_cast(Random::RandomGenerator::max()) * 0.5)); @@ -2518,7 +2613,7 @@ TEST_F(HttpConnectionManagerImplTest, DisableHttp1KeepAliveWhenOverloaded) { .WillByDefault(ReturnRef(disable_http_keep_alive)); codec_->protocol_ = Protocol::Http11; - setup(false, ""); + setup(); EXPECT_CALL(random_, random()) .WillRepeatedly(Return(static_cast(Random::RandomGenerator::max()) * 0.5)); @@ -2567,7 +2662,7 @@ TEST_F(HttpConnectionManagerImplTest, DisableHttp2KeepAliveWhenOverloaded) { .WillByDefault(ReturnRef(disable_http_keep_alive)); codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, shutdownNotice); std::shared_ptr filter(new NiceMock()); @@ -2612,7 +2707,7 @@ TEST_F(HttpConnectionManagerImplTest, CodecCreationLoadShedPointCanCloseConnecti getLoadShedPoint(Server::LoadShedPointName::get().HcmDecodeHeaders)) .WillOnce(Return(nullptr)); - setup(false, ""); + setup(); EXPECT_CALL(close_connection_creating_codec_point, shouldShedLoad()).WillOnce(Return(true)); EXPECT_CALL(filter_callbacks_.connection_, close(_, _)); @@ -2638,7 +2733,7 @@ TEST_F(HttpConnectionManagerImplTest, CodecCreationLoadShedPointBypasscheck) { getLoadShedPoint(Server::LoadShedPointName::get().HttpDownstreamFilterCheck)) .WillOnce(Return(nullptr)); - setup(false, ""); + setup(); EXPECT_CALL(close_connection_creating_codec_point, shouldShedLoad()).WillOnce(Return(false)); @@ -2668,7 +2763,7 @@ TEST_F(HttpConnectionManagerImplTest, DecodeHeaderLoadShedPointCanRejectNewStrea getLoadShedPoint(Server::LoadShedPointName::get().HttpDownstreamFilterCheck)) .WillRepeatedly(Return(nullptr)); - setup(false, ""); + setup(); setupFilterChain(1, 0); EXPECT_CALL(accept_new_stream_point, shouldShedLoad()).WillOnce(Return(true)); @@ -2702,7 +2797,7 @@ TEST_F(HttpConnectionManagerImplTest, DecodeHeaderLoadShedPointCanRejectNewStrea } TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnDecodingPathFirstFilter) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(true, true); // Kick off the incoming data. @@ -2726,7 +2821,7 @@ TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnDecodingPat } TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnDecodingPathSecondFilter) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(true, false); // Verify headers go through both filters, and data and trailers go through the first filter only. @@ -2751,7 +2846,7 @@ TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnDecodingPat } TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnEncodingPath) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -2793,7 +2888,7 @@ TEST_F(HttpConnectionManagerImplTest, TestStopAllIterationAndBufferOnEncodingPat } TEST_F(HttpConnectionManagerImplTest, DisableKeepAliveWhenDraining) { - setup(false, ""); + setup(); EXPECT_CALL(drain_close_, drainClose()).WillOnce(Return(true)); @@ -2832,7 +2927,7 @@ TEST_F(HttpConnectionManagerImplTest, DisableKeepAliveWhenDraining) { } TEST_F(HttpConnectionManagerImplTest, TestSessionTrace) { - setup(false, ""); + setup(); // Set up the codec. EXPECT_CALL(*codec_, dispatch(_)) @@ -2899,7 +2994,7 @@ TEST_F(HttpConnectionManagerImplTest, TestSessionTrace) { // SRDS no scope found. TEST_F(HttpConnectionManagerImplTest, TestSrdsRouteNotFound) { - setup(false, "", true, true); + setup(SetupOpts().setUseSrds(true)); setupFilterChain(1, 0); // Recreate the chain for second stream. EXPECT_CALL(*static_cast(scopeKeyBuilder().ptr()), @@ -2935,7 +3030,7 @@ TEST_F(HttpConnectionManagerImplTest, TestSrdsRouteNotFound) { // SRDS updating scopes affects routing. TEST_F(HttpConnectionManagerImplTest, TestSrdsUpdate) { - setup(false, "", true, true); + setup(SetupOpts().setUseSrds(true)); EXPECT_CALL(*static_cast(scopeKeyBuilder().ptr()), computeScopeKey(_)) @@ -2990,7 +3085,7 @@ TEST_F(HttpConnectionManagerImplTest, TestSrdsUpdate) { // SRDS Scope header update cause cross-scope reroute. TEST_F(HttpConnectionManagerImplTest, TestSrdsCrossScopeReroute) { - setup(false, "", true, true); + setup(SetupOpts().setUseSrds(true)); std::shared_ptr route_config1 = std::make_shared>(); @@ -3063,7 +3158,7 @@ TEST_F(HttpConnectionManagerImplTest, TestSrdsCrossScopeReroute) { // SRDS scoped RouteConfiguration found and route found. TEST_F(HttpConnectionManagerImplTest, TestSrdsRouteFound) { - setup(false, "", true, true); + setup(SetupOpts().setUseSrds(true)); setupFilterChain(1, 0); const std::string fake_cluster1_name = "fake_cluster1"; @@ -3109,7 +3204,7 @@ TEST_F(HttpConnectionManagerImplTest, TestSrdsRouteFound) { } TEST_F(HttpConnectionManagerImplTest, NewConnection) { - setup(false, "", true, true); + setup(SetupOpts().setUseSrds(true)); filter_callbacks_.connection_.stream_info_.protocol_ = absl::nullopt; EXPECT_CALL(filter_callbacks_.connection_.stream_info_, protocol()); @@ -3127,7 +3222,7 @@ TEST_F(HttpConnectionManagerImplTest, NewConnection) { } TEST_F(HttpConnectionManagerImplTest, HeaderOnlyRequestAndResponseUsingHttp3) { - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); filter_callbacks_.connection_.stream_info_.protocol_ = Envoy::Http::Protocol::Http3; codec_->protocol_ = Http::Protocol::Http3; @@ -3195,7 +3290,7 @@ TEST_F(HttpConnectionManagerImplTest, ConnectionFilterState) { "connection_provided_data", std::make_shared(555), StreamInfo::FilterState::StateType::ReadOnly); - setup(false, "envoy-custom-server", false); + setup(SetupOpts().setTracing(false)); setupFilterChain(1, 0, /* num_requests = */ 3); EXPECT_CALL(*codec_, dispatch(_)) @@ -3299,7 +3394,7 @@ class HttpConnectionManagerImplDeathTest : public HttpConnectionManagerImplTest // HCM config can only have either RouteConfigProvider or ScopedRoutesConfigProvider. TEST_F(HttpConnectionManagerImplDeathTest, InvalidConnectionManagerConfig) { - setup(false, ""); + setup(); Buffer::OwnedImpl fake_input("1234"); EXPECT_CALL(*codec_, dispatch(_)).WillRepeatedly(Invoke([&](Buffer::Instance&) -> Http::Status { @@ -3337,7 +3432,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestRejectedViaIPDetection) { use_remote_address_ = false; - setup(false, ""); + setup(); // 403 direct response when IP detection fails. EXPECT_CALL(response_encoder_, encodeHeaders(_, false)) @@ -3354,7 +3449,7 @@ TEST_F(HttpConnectionManagerImplTest, RequestRejectedViaIPDetection) { } TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeHeader) { - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -3376,7 +3471,7 @@ TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeHeader) { } TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeBody) { - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -3405,7 +3500,7 @@ TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeBody) { // Verify that trailers added during a data encoding continuation are not double continued. TEST_F(HttpConnectionManagerImplTest, AddTrailersDuringdDecodingContinue) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -3449,7 +3544,7 @@ TEST_F(HttpConnectionManagerImplTest, AddTrailersDuringdDecodingContinue) { // Verify that trailers added during a data decoding continuation are not double continued. TEST_F(HttpConnectionManagerImplTest, AddTrailersDuringEncodingContinue) { InSequence s; - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); @@ -3489,7 +3584,7 @@ TEST_F(HttpConnectionManagerImplTest, AddTrailersDuringEncodingContinue) { } TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeTrailer) { - setup(false, "envoy-server-test"); + setup(); setupFilterChain(1, 0); EXPECT_CALL(*decoder_filters_[0], decodeHeaders(_, true)) @@ -3520,7 +3615,7 @@ TEST_F(HttpConnectionManagerImplTest, DisconnectDuringEncodeTrailer) { TEST_F(HttpConnectionManagerImplTest, DirectLocalReplyCausesDisconnect) { initial_buffer_limit_ = 10; - setup(false, ""); + setup(); setUpEncoderAndDecoder(false, false); sendRequestHeadersAndData(); @@ -3563,7 +3658,7 @@ TEST_F(HttpConnectionManagerImplTest, DirectLocalReplyCausesDisconnect) { // Header validator rejects header map for HTTP/1.x protocols TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectHttp1) { - setup(false, ""); + setup(); expectUhvHeaderCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_header_map"), ServerHeaderValidator::RequestHeadersTransformationResult::success()); @@ -3609,7 +3704,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectHttp1) { // Header validator rejects header map for HTTP/2 protocols TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectHttp2) { codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); expectUhvHeaderCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_header_map"), ServerHeaderValidator::RequestHeadersTransformationResult::success()); @@ -3638,7 +3733,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectHttp2) { // Header validator rejects gRPC request TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectGrpcRequest) { codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); expectUhvHeaderCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_header_map"), ServerHeaderValidator::RequestHeadersTransformationResult::success()); @@ -3668,7 +3763,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectGrpcRequest) { // Header validator redirects TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRedirect) { - setup(false, ""); + setup(); expectUhvHeaderCheck( HeaderValidator::ValidationResult::success(), ServerHeaderValidator::RequestHeadersTransformationResult( @@ -3698,7 +3793,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRedirect) { // Header validator redirects gRPC request TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRedirectGrpcRequest) { codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); expectUhvHeaderCheck( HeaderValidator::ValidationResult::success(), ServerHeaderValidator::RequestHeadersTransformationResult( @@ -3731,7 +3826,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRedirectGrpcRequest) { // Header validator rejects trailer map before response has started TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersBeforeResponseHttp1) { codec_->protocol_ = Protocol::Http11; - setup(false, ""); + setup(); expectUhvTrailerCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_trailer_map"), HeaderValidator::TransformationResult::success()); @@ -3760,7 +3855,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersBeforeRespons TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersBeforeResponseHttp2) { codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); expectUhvTrailerCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_trailer_map"), HeaderValidator::TransformationResult::success(), false); @@ -3785,7 +3880,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersBeforeRespons TEST_F(HttpConnectionManagerImplTest, HeaderValidatorFailTrailersTransformationBeforeResponse) { codec_->protocol_ = Protocol::Http11; - setup(false, ""); + setup(); expectUhvTrailerCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_trailer_map"), HeaderValidator::TransformationResult::success()); @@ -3815,7 +3910,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorFailTrailersTransformationB // Header validator rejects trailer map after response has started TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersAfterResponse) { codec_->protocol_ = Protocol::Http2; - setup(false, ""); + setup(); setupFilterChain(1, 0, 1); expectUhvTrailerCheck(HeaderValidator::ValidationResult( HeaderValidator::ValidationResult::Action::Reject, "bad_trailer_map"), @@ -3855,7 +3950,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorRejectTrailersAfterResponse // Request completes normally if header validator accepts it TEST_F(HttpConnectionManagerImplTest, HeaderValidatorAccept) { - setup(false, ""); + setup(); expectUhvHeaderCheck(HeaderValidator::ValidationResult::success(), ServerHeaderValidator::RequestHeadersTransformationResult::success()); @@ -3908,7 +4003,7 @@ TEST_F(HttpConnectionManagerImplTest, HeaderValidatorAccept) { TEST_F(HttpConnectionManagerImplTest, NoProxyProtocolAdded) { add_proxy_protocol_connection_state_ = false; - setup(false, "server_name"); + setup(); Buffer::OwnedImpl fake_input("input"); conn_manager_->createCodec(fake_input); @@ -3927,7 +4022,7 @@ TEST_F(HttpConnectionManagerImplTest, LimitWorkPerIOCycle) { EXPECT_CALL(runtime_.snapshot_, getInteger(_, _)).WillRepeatedly(ReturnArg<1>()); // Process 1 request per I/O cycle auto* deferred_request_callback = enableStreamsPerIoLimit(1); - setup(false, ""); + setup(); // Store the basic request encoder during filter chain setup. std::vector> decoder_filters; @@ -4069,7 +4164,7 @@ TEST_F(HttpConnectionManagerImplTest, StreamDeferralPreservesOrder) { EXPECT_CALL(runtime_.snapshot_, getInteger(_, _)).WillRepeatedly(ReturnArg<1>()); // Process 1 request per I/O cycle auto* deferred_request_callback = enableStreamsPerIoLimit(1); - setup(false, ""); + setup(); std::vector> encoder_filters; int expected_request_id = 0; @@ -4179,7 +4274,7 @@ TEST_F(HttpConnectionManagerImplTest, StreamDeferralPreservesOrder) { } TEST_F(HttpConnectionManagerImplTest, DownstreamTimingsRecordWhenRequestHeaderProcessingIsDone) { - setup(/*ssl=*/true, /*server_name=*/"", /*tracing=*/false); + setup(SetupOpts().setSsl(true).setTracing(false)); // Set up the codec. Buffer::OwnedImpl fake_input("input"); @@ -4211,7 +4306,7 @@ TEST_F(HttpConnectionManagerImplTest, DownstreamTimingsRecordWhenRequestHeaderPr } TEST_F(HttpConnectionManagerImplTest, PassMatchUpstreamSchemeHintToStreamInfo) { - setup(/*ssl=*/false, /*server_name=*/"", /*tracing=*/false); + setup(SetupOpts().setTracing(false)); scheme_match_upstream_ = true; // Store the basic request encoder during filter chain setup. diff --git a/test/common/http/conn_manager_impl_test_base.cc b/test/common/http/conn_manager_impl_test_base.cc index 4294d2992955..32cca79b165f 100644 --- a/test/common/http/conn_manager_impl_test_base.cc +++ b/test/common/http/conn_manager_impl_test_base.cc @@ -53,6 +53,9 @@ class ConnectionManagerConfigProxyObject : public ConnectionManagerConfig { absl::optional maxConnectionDuration() const override { return parent_.maxConnectionDuration(); } + bool http1SafeMaxConnectionDuration() const override { + return parent_.http1SafeMaxConnectionDuration(); + } uint32_t maxRequestHeadersKb() const override { return parent_.maxRequestHeadersKb(); } uint32_t maxRequestHeadersCount() const override { return parent_.maxRequestHeadersCount(); } std::chrono::milliseconds streamIdleTimeout() const override { @@ -183,14 +186,14 @@ HttpConnectionManagerImplMixin::requestHeaderCustomTag(const std::string& header return std::make_shared(header, headerTag); } -void HttpConnectionManagerImplMixin::setup(bool ssl, const std::string& server_name, bool tracing, - bool use_srds) { - use_srds_ = use_srds; - if (ssl) { +void HttpConnectionManagerImplMixin::setup(const SetupOpts& opts) { + use_srds_ = opts.use_srds_; + http1_safe_max_connection_duration_ = opts.http1_safe_max_connection_duration_; + if (opts.ssl_) { ssl_connection_ = std::make_shared(); } - server_name_ = server_name; + server_name_ = opts.server_name_; ON_CALL(filter_callbacks_.connection_, ssl()).WillByDefault(Return(ssl_connection_)); ON_CALL(Const(filter_callbacks_.connection_), ssl()).WillByDefault(Return(ssl_connection_)); ON_CALL(filter_callbacks_.connection_.dispatcher_, createScaledTypedTimer_) @@ -214,7 +217,7 @@ void HttpConnectionManagerImplMixin::setup(bool ssl, const std::string& server_n conn_manager_->initializeReadFilterCallbacks(filter_callbacks_); - if (tracing) { + if (opts.tracing_) { envoy::type::v3::FractionalPercent percent1; percent1.set_numerator(100); envoy::type::v3::FractionalPercent percent2; @@ -421,7 +424,7 @@ void HttpConnectionManagerImplMixin::doRemoteClose(bool deferred) { void HttpConnectionManagerImplMixin::testPathNormalization( const RequestHeaderMap& request_headers, const ResponseHeaderMap& expected_response) { - setup(false, ""); + setup(); EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance& data) -> Http::Status { decoder_ = &conn_manager_->newStream(response_encoder_); diff --git a/test/common/http/conn_manager_impl_test_base.h b/test/common/http/conn_manager_impl_test_base.h index 5e24d36a926f..4be397ffb578 100644 --- a/test/common/http/conn_manager_impl_test_base.h +++ b/test/common/http/conn_manager_impl_test_base.h @@ -29,6 +29,38 @@ using testing::NiceMock; namespace Envoy { namespace Http { +struct SetupOpts { + SetupOpts& setSsl(bool ssl) { + ssl_ = ssl; + return *this; + } + + SetupOpts& setServerName(absl::string_view server_name) { + server_name_ = server_name; + return *this; + } + + SetupOpts& setTracing(bool tracing) { + tracing_ = tracing; + return *this; + } + + SetupOpts& setUseSrds(bool use_srds) { + use_srds_ = use_srds; + return *this; + } + + SetupOpts& setHttp1SafeMaxConnectionDuration(bool http1_safe_max_connection_duration) { + http1_safe_max_connection_duration_ = http1_safe_max_connection_duration; + return *this; + } + + bool ssl_{false}; + std::string server_name_{"envoy-server-test"}; + bool tracing_{true}; + bool use_srds_{false}; + bool http1_safe_max_connection_duration_{false}; +}; // Base class for HttpConnectionManagerImpl related tests. This base class is used by tests under // common/http as well as test/extensions/filters/http/ext_proc/, to reuse the many mocks/default // impls of ConnectionManagerConfig that we need to provide to HttpConnectionManagerImpl. @@ -37,7 +69,7 @@ class HttpConnectionManagerImplMixin : public ConnectionManagerConfig { HttpConnectionManagerImplMixin(); ~HttpConnectionManagerImplMixin() override; Tracing::CustomTagConstSharedPtr requestHeaderCustomTag(const std::string& header); - void setup(bool ssl, const std::string& server_name, bool tracing = true, bool use_srds = false); + void setup(const SetupOpts& opts = {}); void setupFilterChain(int num_decoder_filters, int num_encoder_filters, int num_requests = 1); void setUpBufferLimits(); @@ -86,6 +118,9 @@ class HttpConnectionManagerImplMixin : public ConnectionManagerConfig { absl::optional maxConnectionDuration() const override { return max_connection_duration_; } + bool http1SafeMaxConnectionDuration() const override { + return http1_safe_max_connection_duration_; + } std::chrono::milliseconds streamIdleTimeout() const override { return stream_idle_timeout_; } std::chrono::milliseconds requestTimeout() const override { return request_timeout_; } std::chrono::milliseconds requestHeadersTimeout() const override { @@ -248,6 +283,7 @@ class HttpConnectionManagerImplMixin : public ConnectionManagerConfig { uint64_t max_requests_per_connection_{}; absl::optional idle_timeout_; absl::optional max_connection_duration_; + bool http1_safe_max_connection_duration_{false}; std::chrono::milliseconds stream_idle_timeout_{}; std::chrono::milliseconds request_timeout_{}; std::chrono::milliseconds request_headers_timeout_{}; diff --git a/test/common/http/conn_pool_grid_test.cc b/test/common/http/conn_pool_grid_test.cc index 476e6730b9dc..dd14534da4a6 100644 --- a/test/common/http/conn_pool_grid_test.cc +++ b/test/common/http/conn_pool_grid_test.cc @@ -4,6 +4,7 @@ #include "source/common/http/conn_pool_grid.h" #include "source/common/http/http_server_properties_cache_impl.h" +#include "source/common/upstream/transport_socket_match_impl.h" #include "test/common/http/common.h" #include "test/common/upstream/utility.h" @@ -51,6 +52,8 @@ class ConnectivityGridForTest : public ConnectivityGrid { return grid.getOrCreateHttp2Pool(); } + std::string getOriginHostname() { return origin_.hostname_; } + ConnectionPool::InstancePtr createHttp3Pool(bool alternate) override { if (!alternate) { return createMockPool("http3"); @@ -177,8 +180,8 @@ class ConnectivityGridTest : public Event::TestUsingSimulatedTime, public testin std::make_unique(); #endif host_ = std::make_shared( - cluster_, "hostname", *Network::Utility::resolveUrl("tcp://127.0.0.1:9000"), nullptr, - nullptr, 1, envoy::config::core::v3::Locality(), + cluster_, host_impl_hostname_, *Network::Utility::resolveUrl("tcp://127.0.0.1:9000"), + nullptr, nullptr, 1, envoy::config::core::v3::Locality(), envoy::config::endpoint::v3::Endpoint::HealthCheckConfig::default_instance(), 0, envoy::config::core::v3::UNKNOWN, simTime(), address_list_); @@ -213,7 +216,7 @@ class ConnectivityGridTest : public Event::TestUsingSimulatedTime, public testin HttpServerPropertiesCacheImpl::Origin origin_{"https", "hostname", 9000}; const Network::ConnectionSocket::OptionsSharedPtr socket_options_; - const Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; + Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; ConnectivityGrid::ConnectivityOptions options_; Upstream::ClusterConnectivityState state_; std::shared_ptr cluster_{new NiceMock()}; @@ -236,11 +239,40 @@ class ConnectivityGridTest : public Event::TestUsingSimulatedTime, public testin testing::NiceMock thread_local_; NiceMock dispatcher_; std::unique_ptr grid_; + std::string host_impl_hostname_ = "hostname"; }; +TEST_F(ConnectivityGridTest, HostnameFromTransportSocketFactory) { + Network::MockTransportSocketFactory factory; + Upstream::MockTransportSocketMatcher* transport_socket_matcher = + dynamic_cast( + cluster_->transport_socket_matcher_.get()); + EXPECT_CALL(*transport_socket_matcher, resolve(_, _)) + .WillOnce(Return(Upstream::TransportSocketMatcher::MatchData( + factory, transport_socket_matcher->stats_, "test"))); + EXPECT_CALL(factory, defaultServerNameIndication) + .WillRepeatedly(Return("transport_socket_hostname")); + host_impl_hostname_ = "custom_hostname"; + transport_socket_options_ = std::make_shared(); + initialize(); + // Without "hostname" in the TransportSocketOptionsImpl, this fails over to + // the host name in HostNameImpl + EXPECT_EQ("transport_socket_hostname", grid_->getOriginHostname()); +} + +TEST_F(ConnectivityGridTest, NoServerNameOverride) { + host_impl_hostname_ = "custom_hostname"; + transport_socket_options_ = std::make_shared(); + initialize(); + // Without "hostname" in the TransportSocketOptionsImpl, this fails over to + // the host name in HostNameImpl + EXPECT_EQ(host_impl_hostname_, grid_->getOriginHostname()); +} + // Test the first pool successfully connecting. TEST_F(ConnectivityGridTest, Success) { initialize(); + EXPECT_EQ("hostname", grid_->getOriginHostname()); addHttp3AlternateProtocol(); EXPECT_EQ(grid_->http3Pool(), nullptr); EXPECT_NE(grid_->newStream(decoder_, callbacks_, diff --git a/test/common/http/filter_chain_helper_test.cc b/test/common/http/filter_chain_helper_test.cc index 75483f21cd68..dd8c36985d58 100644 --- a/test/common/http/filter_chain_helper_test.cc +++ b/test/common/http/filter_chain_helper_test.cc @@ -28,10 +28,8 @@ TEST(FilterChainUtilityTest, CreateFilterChainForFactoriesWithRouteDisabled) { for (const auto& name : {"filter_0", "filter_1", "filter_2"}) { auto provider = - std::make_unique>( - Filter::NamedHttpFilterFactoryCb{"filter_type_name", - [](FilterChainFactoryCallbacks&) {}}, - name); + std::make_unique>( + [](FilterChainFactoryCallbacks&) {}, name); filter_factories.push_back({std::move(provider), false}); } @@ -61,10 +59,8 @@ TEST(FilterChainUtilityTest, CreateFilterChainForFactoriesWithRouteDisabledAndDe for (const auto& name : {"filter_0", "filter_1", "filter_2"}) { auto provider = - std::make_unique>( - Filter::NamedHttpFilterFactoryCb{"filter_type_name", - [](FilterChainFactoryCallbacks&) {}}, - name); + std::make_unique>( + [](FilterChainFactoryCallbacks&) {}, name); filter_factories.push_back({std::move(provider), true}); } diff --git a/test/common/http/filter_manager_test.cc b/test/common/http/filter_manager_test.cc index c360ed655c6a..d310d73873db 100644 --- a/test/common/http/filter_manager_test.cc +++ b/test/common/http/filter_manager_test.cc @@ -168,7 +168,7 @@ TEST_F(FilterManagerTest, SendLocalReplyDuringDecodingGrpcClassiciation) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto factory = createDecoderFilterFactoryCb(filter); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, factory); + manager.applyFilterFactoryCb({"configName1"}, factory); return true; })); @@ -222,10 +222,10 @@ TEST_F(FilterManagerTest, SendLocalReplyDuringEncodingGrpcClassiciation) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createDecoderFilterFactoryCb(decoder_filter); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, decoder_factory); + manager.applyFilterFactoryCb({"configName1"}, decoder_factory); auto stream_factory = createStreamFilterFactoryCb(encoder_filter); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, stream_factory); + manager.applyFilterFactoryCb({"configName2"}, stream_factory); return true; })); @@ -272,11 +272,11 @@ TEST_F(FilterManagerTest, OnLocalReply) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createDecoderFilterFactoryCb(decoder_filter); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, decoder_factory); + manager.applyFilterFactoryCb({"configName1"}, decoder_factory); auto stream_factory = createStreamFilterFactoryCb(stream_filter); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, stream_factory); + manager.applyFilterFactoryCb({"configName2"}, stream_factory); auto encoder_factory = createEncoderFilterFactoryCb(encoder_filter); - manager.applyFilterFactoryCb({"configName3", "filterName3"}, encoder_factory); + manager.applyFilterFactoryCb({"configName3"}, encoder_factory); return true; })); @@ -335,11 +335,11 @@ TEST_F(FilterManagerTest, MultipleOnLocalReply) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createDecoderFilterFactoryCb(decoder_filter); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, decoder_factory); + manager.applyFilterFactoryCb({"configName1"}, decoder_factory); auto stream_factory = createStreamFilterFactoryCb(stream_filter); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, stream_factory); + manager.applyFilterFactoryCb({"configName2"}, stream_factory); auto encoder_factory = createEncoderFilterFactoryCb(encoder_filter); - manager.applyFilterFactoryCb({"configName3", "filterName3"}, encoder_factory); + manager.applyFilterFactoryCb({"configName3"}, encoder_factory); return true; })); @@ -437,7 +437,7 @@ TEST_F(FilterManagerTest, GetRouteLevelFilterConfig) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createDecoderFilterFactoryCb(decoder_filter); - manager.applyFilterFactoryCb({"custom-name", "filter-name"}, decoder_factory); + manager.applyFilterFactoryCb({"custom-name"}, decoder_factory); return true; })); filter_manager_->createFilterChain(); @@ -491,7 +491,7 @@ TEST_F(FilterManagerTest, GetRouteLevelFilterConfigForNullRoute) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createDecoderFilterFactoryCb(decoder_filter); - manager.applyFilterFactoryCb({"custom-name", "filter-name"}, decoder_factory); + manager.applyFilterFactoryCb({"custom-name"}, decoder_factory); return true; })); filter_manager_->createFilterChain(); @@ -523,9 +523,9 @@ TEST_F(FilterManagerTest, MetadataContinueAll) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createStreamFilterFactoryCb(filter_1); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, decoder_factory); + manager.applyFilterFactoryCb({"configName1"}, decoder_factory); decoder_factory = createStreamFilterFactoryCb(filter_2); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, decoder_factory); + manager.applyFilterFactoryCb({"configName2"}, decoder_factory); return true; })); filter_manager_->createFilterChain(); @@ -595,9 +595,9 @@ TEST_F(FilterManagerTest, DecodeMetadataSendsLocalReply) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto factory = createStreamFilterFactoryCb(filter_1); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, factory); + manager.applyFilterFactoryCb({"configName1"}, factory); factory = createStreamFilterFactoryCb(filter_2); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, factory); + manager.applyFilterFactoryCb({"configName2"}, factory); return true; })); filter_manager_->createFilterChain(); @@ -642,9 +642,9 @@ TEST_F(FilterManagerTest, MetadataContinueAllFollowedByHeadersLocalReply) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto decoder_factory = createStreamFilterFactoryCb(filter_1); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, decoder_factory); + manager.applyFilterFactoryCb({"configName1"}, decoder_factory); decoder_factory = createStreamFilterFactoryCb(filter_2); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, decoder_factory); + manager.applyFilterFactoryCb({"configName2"}, decoder_factory); return true; })); filter_manager_->createFilterChain(); @@ -682,9 +682,9 @@ TEST_F(FilterManagerTest, EncodeMetadataSendsLocalReply) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto factory = createStreamFilterFactoryCb(filter_1); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, factory); + manager.applyFilterFactoryCb({"configName1"}, factory); factory = createStreamFilterFactoryCb(filter_2); - manager.applyFilterFactoryCb({"configName2", "filterName2"}, factory); + manager.applyFilterFactoryCb({"configName2"}, factory); return true; })); filter_manager_->createFilterChain(); @@ -721,7 +721,7 @@ TEST_F(FilterManagerTest, IdleTimerResets) { EXPECT_CALL(filter_factory_, createFilterChain(_)) .WillRepeatedly(Invoke([&](FilterChainManager& manager) -> bool { auto factory = createStreamFilterFactoryCb(filter_1); - manager.applyFilterFactoryCb({"configName1", "filterName1"}, factory); + manager.applyFilterFactoryCb({"configName1"}, factory); return true; })); filter_manager_->createFilterChain(); diff --git a/test/common/http/header_utility_test.cc b/test/common/http/header_utility_test.cc index 971f0e953f68..577f36eea951 100644 --- a/test/common/http/header_utility_test.cc +++ b/test/common/http/header_utility_test.cc @@ -1152,6 +1152,24 @@ TEST(HeaderIsValidTest, ValidHeaderValuesAreAccepted) { TEST(HeaderIsValidTest, AuthorityIsValid) { EXPECT_TRUE(HeaderUtility::authorityIsValid("strangebutlegal$-%&'")); EXPECT_FALSE(HeaderUtility::authorityIsValid("illegal{}")); + // Validate that the "@" character is allowed. + // TODO(adisuissa): Once the envoy.reloadable_features.internal_authority_header_validator + // runtime flag is deprecated, this test should only validate the assignment + // to "true". + { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.internal_authority_header_validator", "true"}}); + EXPECT_TRUE(HeaderUtility::authorityIsValid("username@example.com'")); + } + { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues( + {{"envoy.reloadable_features.internal_authority_header_validator", "false"}}); + // When the above is false, Envoy should use oghttp2's validator which will + // reject the "@" character. + EXPECT_FALSE(HeaderUtility::authorityIsValid("username@example.com'")); + } } TEST(HeaderIsValidTest, IsConnect) { diff --git a/test/common/http/http_server_properties_cache_impl_test.cc b/test/common/http/http_server_properties_cache_impl_test.cc index 3efb2ae0646b..bcbf40ac3ec8 100644 --- a/test/common/http/http_server_properties_cache_impl_test.cc +++ b/test/common/http/http_server_properties_cache_impl_test.cc @@ -48,6 +48,7 @@ class HttpServerPropertiesCacheImplTest : public testing::TestWithParamgetOrCreateHttp3StatusTracker(origin1_).markHttp3Broken(); EXPECT_EQ(1u, protocols_->size()); EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin1_).isHttp3Broken()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin1_).isHttp3Broken()); - // Fetch HTTP/3 status for another origin should overwrite the cache. + // Fetch HTTP/3 status for another origin should overwrite the cache because + // it's limited to one entry. EXPECT_FALSE(protocols_->getOrCreateHttp3StatusTracker(origin2_).isHttp3Broken()); EXPECT_EQ(1u, protocols_->size()); EXPECT_FALSE(protocols_->getOrCreateHttp3StatusTracker(origin1_).isHttp3Broken()); } +TEST_P(HttpServerPropertiesCacheImplTest, ClearBrokenness) { + initialize(); + EXPECT_EQ(0u, protocols_->size()); + + protocols_->getOrCreateHttp3StatusTracker(origin1_).markHttp3Broken(); + protocols_->getOrCreateHttp3StatusTracker(origin2_).markHttp3Confirmed(); + protocols_->getOrCreateHttp3StatusTracker(origin3_).markHttp3Broken(); + + EXPECT_EQ(3u, protocols_->size()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin1_).isHttp3Broken()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin3_).isHttp3Broken()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin2_).isHttp3Confirmed()); + + protocols_->resetBrokenness(); + + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin1_).hasHttp3FailedRecently()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin3_).hasHttp3FailedRecently()); + EXPECT_TRUE(protocols_->getOrCreateHttp3StatusTracker(origin2_).isHttp3Confirmed()); +} + TEST_P(HttpServerPropertiesCacheImplTest, CanonicalSuffix) { std::string suffix = ".example.com"; std::string host1 = "first.example.com"; diff --git a/test/common/http/http_server_properties_cache_manager_test.cc b/test/common/http/http_server_properties_cache_manager_test.cc index e29d8ac47349..cfad02480867 100644 --- a/test/common/http/http_server_properties_cache_manager_test.cc +++ b/test/common/http/http_server_properties_cache_manager_test.cc @@ -94,6 +94,15 @@ TEST_F(HttpServerPropertiesCacheManagerTest, GetCacheForDifferentOptions) { HttpServerPropertiesCacheSharedPtr cache2 = manager_->getCache(options2_, dispatcher_); EXPECT_NE(nullptr, cache2); EXPECT_NE(cache1, cache2); + + int num_caches = 0; + Http::HttpServerPropertiesCacheManager::CacheFn count_caches = + [&](Http::HttpServerPropertiesCache& cache) { + EXPECT_TRUE(&cache == cache1.get() || &cache == cache2.get()); + ++num_caches; + }; + manager_->forEachThreadLocalCache(count_caches); + EXPECT_EQ(num_caches, 2); } TEST_F(HttpServerPropertiesCacheManagerTest, GetCacheForConflictingOptions) { diff --git a/test/common/orca/BUILD b/test/common/orca/BUILD new file mode 100644 index 000000000000..ea012a118e6b --- /dev/null +++ b/test/common/orca/BUILD @@ -0,0 +1,43 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "orca_load_metrics_test", + srcs = ["orca_load_metrics_test.cc"], + external_deps = [ + "abseil_status", + "abseil_strings", + "fmtlib", + ], + deps = [ + "//source/common/orca:orca_load_metrics_lib", + "//source/common/upstream:upstream_lib", + "//test/test_common:status_utility_lib", + "//test/test_common:utility_lib", + "@com_github_cncf_xds//xds/data/orca/v3:pkg_cc_proto", + ], +) + +envoy_cc_test( + name = "orca_parser_test", + srcs = ["orca_parser_test.cc"], + external_deps = [ + "abseil_status", + "abseil_strings", + "fmtlib", + ], + deps = [ + "//source/common/common:base64_lib", + "//source/common/orca:orca_parser", + "//test/test_common:status_utility_lib", + "//test/test_common:utility_lib", + "@com_github_cncf_xds//xds/data/orca/v3:pkg_cc_proto", + ], +) diff --git a/test/common/orca/orca_load_metrics_test.cc b/test/common/orca/orca_load_metrics_test.cc new file mode 100644 index 000000000000..cce62960437e --- /dev/null +++ b/test/common/orca/orca_load_metrics_test.cc @@ -0,0 +1,136 @@ +#include "source/common/orca/orca_load_metrics.h" +#include "source/common/upstream/upstream_impl.h" + +#include "test/test_common/status_utility.h" +#include "test/test_common/utility.h" + +using ::Envoy::Upstream::LoadMetricStats; +using ::Envoy::Upstream::LoadMetricStatsImpl; +using ::testing::DoubleEq; +using ::testing::Field; +using ::testing::ReturnRef; + +namespace Envoy { +namespace Orca { +namespace { + +xds::data::orca::v3::OrcaLoadReport makeOrcaReport() { + xds::data::orca::v3::OrcaLoadReport report; + report.mutable_named_metrics()->insert({"nm_foo", 0.1}); + report.mutable_named_metrics()->insert({"nm_bar", 0.2}); + report.mutable_request_cost()->insert({"rc_foo", 0.4}); + report.mutable_request_cost()->insert({"rc_bar", 0.5}); + report.mutable_utilization()->insert({"ut_foo", 0.6}); + report.mutable_utilization()->insert({"ut_bar", 0.7}); + report.set_application_utilization(0.8); + report.set_cpu_utilization(0.9); + report.set_mem_utilization(1.0); + report.set_eps(10); + report.set_rps_fractional(11); + return report; +} + +TEST(OrcaLoadMetricsTest, AddCpuUtilization) { + Envoy::Orca::LrsReportMetricNames metric_names; + metric_names.push_back("cpu_utilization"); + + Envoy::Upstream::LoadMetricStatsImpl stats; + Envoy::Orca::addOrcaLoadReportToLoadMetricStats(metric_names, makeOrcaReport(), stats); + auto load_stats_map = stats.latch(); + ASSERT_NE(load_stats_map, nullptr); + EXPECT_EQ(load_stats_map->size(), 1); + + EXPECT_EQ(load_stats_map->at("cpu_utilization").total_metric_value, 0.9); + EXPECT_EQ(load_stats_map->at("cpu_utilization").num_requests_with_metric, 1); +} + +TEST(OrcaLoadMetricsTest, AddSpecificNamedMetrics) { + Envoy::Orca::LrsReportMetricNames metric_names; + metric_names.push_back("named_metrics.foo"); + metric_names.push_back("named_metrics.not-in-report"); + + xds::data::orca::v3::OrcaLoadReport report; + report.mutable_named_metrics()->insert({"foo", 0.7}); + report.mutable_named_metrics()->insert({"not-in-config", 0.3}); + + Envoy::Upstream::LoadMetricStatsImpl stats; + Envoy::Orca::addOrcaLoadReportToLoadMetricStats(metric_names, report, stats); + auto load_stats_map = stats.latch(); + ASSERT_NE(load_stats_map, nullptr); + EXPECT_EQ(load_stats_map->size(), 1); + EXPECT_EQ(load_stats_map->at("named_metrics.foo").total_metric_value, 0.7); +} + +TEST(OrcaLoadMetricsTest, AddWildcardUtilization) { + Envoy::Orca::LrsReportMetricNames metric_names; + metric_names.push_back("utilization.*"); + + Envoy::Upstream::LoadMetricStatsImpl stats; + Envoy::Orca::addOrcaLoadReportToLoadMetricStats(metric_names, makeOrcaReport(), stats); + auto load_stats_map = stats.latch(); + ASSERT_NE(load_stats_map, nullptr); + EXPECT_THAT(*load_stats_map, + UnorderedElementsAre( + Pair("utilization.ut_foo", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.6)))), + Pair("utilization.ut_bar", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.7)))))); +} + +TEST(OrcaLoadMetricsTest, AddAllReportedMetrics) { + Envoy::Orca::LrsReportMetricNames metric_names; + metric_names.push_back("application_utilization"); + metric_names.push_back("cpu_utilization"); + metric_names.push_back("mem_utilization"); + metric_names.push_back("eps"); + metric_names.push_back("rps_fractional"); + metric_names.push_back("named_metrics.*"); + metric_names.push_back("utilization.*"); + metric_names.push_back("request_cost.*"); + + Envoy::Upstream::LoadMetricStatsImpl stats; + Envoy::Orca::addOrcaLoadReportToLoadMetricStats(metric_names, makeOrcaReport(), stats); + auto load_stats_map = stats.latch(); + ASSERT_NE(load_stats_map, nullptr); + EXPECT_THAT( + *load_stats_map, + UnorderedElementsAre( + Pair("named_metrics.nm_foo", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.1)))), + Pair("named_metrics.nm_bar", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.2)))), + Pair("request_cost.rc_foo", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.4)))), + Pair("request_cost.rc_bar", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.5)))), + Pair("utilization.ut_foo", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.6)))), + Pair("utilization.ut_bar", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.7)))), + Pair("application_utilization", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.8)))), + Pair("cpu_utilization", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(0.9)))), + Pair("mem_utilization", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(1.0)))), + Pair("eps", AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(10)))), + Pair("rps_fractional", + AllOf(Field(&LoadMetricStats::Stat::num_requests_with_metric, 1), + Field(&LoadMetricStats::Stat::total_metric_value, DoubleEq(11)))))); +} + +} // namespace +} // namespace Orca +} // namespace Envoy diff --git a/test/common/orca/orca_parser_test.cc b/test/common/orca/orca_parser_test.cc new file mode 100644 index 000000000000..84debabd85ed --- /dev/null +++ b/test/common/orca/orca_parser_test.cc @@ -0,0 +1,72 @@ +#include + +#include "source/common/common/base64.h" +#include "source/common/orca/orca_parser.h" + +#include "test/test_common/status_utility.h" +#include "test/test_common/utility.h" + +#include "absl/status/status.h" +#include "xds/data/orca/v3/orca_load_report.pb.h" + +namespace Envoy { +namespace Orca { +namespace { + +// Returns an example OrcaLoadReport proto with all fields populated. +static xds::data::orca::v3::OrcaLoadReport exampleOrcaLoadReport() { + xds::data::orca::v3::OrcaLoadReport orca_load_report; + orca_load_report.set_cpu_utilization(0.7); + orca_load_report.set_application_utilization(0.8); + orca_load_report.set_mem_utilization(0.9); + orca_load_report.set_eps(2); + orca_load_report.set_rps_fractional(1000); + orca_load_report.mutable_named_metrics()->insert({"foo", 123}); + orca_load_report.mutable_named_metrics()->insert({"bar", 0.2}); + return orca_load_report; +} + +TEST(OrcaParserUtilTest, NoHeaders) { + Http::TestRequestHeaderMapImpl headers{}; + // parseOrcaLoadReport returns error when no ORCA data is sent from + // the backend. + EXPECT_THAT(parseOrcaLoadReportHeaders(headers), + StatusHelpers::HasStatus(absl::NotFoundError("no ORCA data sent from the backend"))); +} + +TEST(OrcaParserUtilTest, MissingOrcaHeaders) { + Http::TestRequestHeaderMapImpl headers{{"wrong-header", "wrong-value"}}; + // parseOrcaLoadReport returns error when no ORCA data is sent from + // the backend. + EXPECT_THAT(parseOrcaLoadReportHeaders(headers), + StatusHelpers::HasStatus(absl::NotFoundError("no ORCA data sent from the backend"))); +} + +TEST(OrcaParserUtilTest, BinaryHeader) { + const std::string proto_string = + TestUtility::getProtobufBinaryStringFromMessage(exampleOrcaLoadReport()); + const auto orca_load_report_header_bin = + Envoy::Base64::encode(proto_string.c_str(), proto_string.length()); + Http::TestRequestHeaderMapImpl headers{ + {std::string(kEndpointLoadMetricsHeaderBin), orca_load_report_header_bin}}; + EXPECT_THAT(parseOrcaLoadReportHeaders(headers), + StatusHelpers::IsOkAndHolds(ProtoEq(exampleOrcaLoadReport()))); +} + +TEST(OrcaParserUtilTest, InvalidBinaryHeader) { + const std::string proto_string = + TestUtility::getProtobufBinaryStringFromMessage(exampleOrcaLoadReport()); + // Force a bad base64 encoding by shortening the length of the output. + const auto orca_load_report_header_bin = + Envoy::Base64::encode(proto_string.c_str(), proto_string.length() / 2); + Http::TestRequestHeaderMapImpl headers{ + {std::string(kEndpointLoadMetricsHeaderBin), orca_load_report_header_bin}}; + EXPECT_THAT(parseOrcaLoadReportHeaders(headers), + StatusHelpers::HasStatus( + absl::StatusCode::kInvalidArgument, + testing::HasSubstr("unable to parse binaryheader to OrcaLoadReport"))); +} + +} // namespace +} // namespace Orca +} // namespace Envoy diff --git a/test/common/quic/active_quic_listener_test.cc b/test/common/quic/active_quic_listener_test.cc index ce68869cf538..84b637abc5e1 100644 --- a/test/common/quic/active_quic_listener_test.cc +++ b/test/common/quic/active_quic_listener_test.cc @@ -127,7 +127,7 @@ class ActiveQuicListenerTest : public testing::TestWithParamallocateDispatcher("test_thread")), clock_(*dispatcher_), - local_address_(Network::Test::getCanonicalLoopbackAddress(version_)), + local_address_(Network::Test::getAnyAddress(version_, true)), connection_handler_(*dispatcher_, absl::nullopt), transport_socket_factory_(*Quic::QuicServerTransportSocketFactory::create( true, *store_.rootScope(), std::make_unique>(), @@ -259,14 +259,22 @@ class ActiveQuicListenerTest : public testing::TestWithParam(Network::Socket::Type::Datagram, local_address_, + std::make_unique(Network::Socket::Type::Datagram, client_address, nullptr, Network::SocketCreationOptions{})); // Set outgoing ECN marks on client packets. int level = IPPROTO_IP; int optname = IP_TOS; - if (local_address_->ip()->version() == Network::Address::IpVersion::v6) { + if (client_address->ip()->version() == Network::Address::IpVersion::v6) { level = IPPROTO_IPV6; optname = IPV6_TCLASS; } @@ -276,10 +284,21 @@ class ActiveQuicListenerTest : public testing::TestWithParamip()->version() == Network::Address::IpVersion::v4) { + dest_address = std::make_shared( + client_address->ip()->addressAsString(), + listen_socket_->connectionInfoProvider().localAddress()->ip()->port(), + &(listen_socket_->connectionInfoProvider().localAddress()->socketInterface())); + } else { + dest_address = std::make_shared( + client_address->ip()->addressAsString(), + listen_socket_->connectionInfoProvider().localAddress()->ip()->port(), + &(listen_socket_->connectionInfoProvider().localAddress()->socketInterface())); + } // Send a full CHLO to finish 0-RTT handshake. - auto send_rc = Network::Utility::writeToSocket( - client_sockets_.back()->ioHandle(), slice.data(), 1, nullptr, - *listen_socket_->connectionInfoProvider().localAddress()); + auto send_rc = Network::Utility::writeToSocket(client_sockets_.back()->ioHandle(), slice.data(), + 1, nullptr, *dest_address); ASSERT_EQ(slice[0].len_, send_rc.return_value_); } @@ -603,14 +622,23 @@ TEST_P(ActiveQuicListenerTest, EcnReportingIsEnabled) { Network::Socket& socket = ActiveQuicListenerPeer::socket(*quic_listener_); absl::optional version = socket.ipVersion(); EXPECT_TRUE(version.has_value()); - int optval; + int optval = 0; socklen_t optlen = sizeof(optval); Api::SysCallIntResult rv; if (*version == Network::Address::IpVersion::v6) { rv = socket.getSocketOption(IPPROTO_IPV6, IPV6_RECVTCLASS, &optval, &optlen); - } else { - rv = socket.getSocketOption(IPPROTO_IP, IP_RECVTOS, &optval, &optlen); + EXPECT_EQ(rv.return_value_, 0); + EXPECT_EQ(optval, 1); + EXPECT_FALSE(local_address_->ip()->ipv6()->v6only()); +#ifdef __APPLE__ + return; +#endif // __APPLE__ } + // Check the IPv4 version of the sockopt if the socket is v4 or dual-stack. + // Platform/ APIs for ECN reporting are poorly documented, but this test + // should uncover any issues. + optval = 0; + rv = socket.getSocketOption(IPPROTO_IP, IP_RECVTOS, &optval, &optlen); EXPECT_EQ(rv.return_value_, 0); EXPECT_EQ(optval, 1); } @@ -630,6 +658,24 @@ TEST_P(ActiveQuicListenerTest, EcnReporting) { EXPECT_EQ(stats.num_ecn_marks_received.ect1, 1); } +TEST_P(ActiveQuicListenerTest, EcnReportingDualStack) { + if (local_address_->ip()->version() == Network::Address::IpVersion::v4) { + return; + } + Runtime::maybeSetRuntimeGuard("envoy.reloadable_features.quic_receive_ecn", true); + initialize(); + maybeConfigureMocks(/* connection_count = */ 1); + quic::QuicConnectionId connection_id = quic::test::TestConnectionId(1); + sendCHLO(connection_id, /*dual_stack=*/true); + dispatcher_->run(Event::Dispatcher::RunType::Block); + quic::QuicConnection* connection = + quic::test::QuicDispatcherPeer::GetFirstSessionIfAny(quic_dispatcher_)->connection(); + EXPECT_EQ(connection->connection_id(), quic::test::TestConnectionId(1)); + ASSERT(connection != nullptr); + const quic::QuicConnectionStats& stats = connection->GetStats(); + EXPECT_EQ(stats.num_ecn_marks_received.ect1, 1); +} + class ActiveQuicListenerEmptyFlagConfigTest : public ActiveQuicListenerTest { protected: std::string yamlForQuicConfig() override { diff --git a/test/common/quic/envoy_quic_h3_fuzz_helper.cc b/test/common/quic/envoy_quic_h3_fuzz_helper.cc index 30f4f69e66e1..a129446aaf31 100644 --- a/test/common/quic/envoy_quic_h3_fuzz_helper.cc +++ b/test/common/quic/envoy_quic_h3_fuzz_helper.cc @@ -27,7 +27,8 @@ class Delegate : public quic::QpackEncoder::DecoderStreamErrorDelegate { static std::string encodeHeaders(const spdy::Http2HeaderBlock& headers) { static Delegate delegate; - quic::QpackEncoder encoder(&delegate, quic::HuffmanEncoding::kEnabled); + quic::QpackEncoder encoder(&delegate, quic::HuffmanEncoding::kEnabled, + quic::CookieCrumbling::kEnabled); return encoder.EncodeHeaderList(0, headers, nullptr); } diff --git a/test/common/quic/envoy_quic_server_session_test.cc b/test/common/quic/envoy_quic_server_session_test.cc index 4fba3ac27b03..b670a20d8702 100644 --- a/test/common/quic/envoy_quic_server_session_test.cc +++ b/test/common/quic/envoy_quic_server_session_test.cc @@ -376,6 +376,10 @@ TEST_F(EnvoyQuicServerSessionTest, OnResetFrameIetfQuic) { listener_config_.listenerScope().store(), "http3.downstream.rx.quic_reset_stream_error_code_QUIC_ERROR_PROCESSING_STREAM") ->value()); + EXPECT_EQ(nullptr, + TestUtility::findCounter( + listener_config_.listenerScope().store(), + "http3.downstream.tx.quic_reset_stream_error_code_QUIC_ERROR_PROCESSING_STREAM")); EXPECT_CALL(http_connection_callbacks_, newStream(_, false)) .WillOnce(Invoke([&request_decoder, &stream_callbacks](Http::ResponseEncoder& encoder, @@ -403,6 +407,9 @@ TEST_F(EnvoyQuicServerSessionTest, OnResetFrameIetfQuic) { listener_config_.listenerScope().store(), "http3.downstream.rx.quic_reset_stream_error_code_QUIC_REFUSED_STREAM") ->value()); + EXPECT_EQ(nullptr, TestUtility::findCounter( + listener_config_.listenerScope().store(), + "http3.downstream.tx.quic_reset_stream_error_code_QUIC_REFUSED_STREAM")); EXPECT_CALL(http_connection_callbacks_, newStream(_, false)) .WillOnce(Invoke([&request_decoder, &stream_callbacks](Http::ResponseEncoder& encoder, @@ -424,6 +431,30 @@ TEST_F(EnvoyQuicServerSessionTest, OnResetFrameIetfQuic) { listener_config_.listenerScope().store(), "http3.downstream.rx.quic_reset_stream_error_code_QUIC_REFUSED_STREAM") ->value()); + EXPECT_EQ(nullptr, TestUtility::findCounter( + listener_config_.listenerScope().store(), + "http3.downstream.tx.quic_reset_stream_error_code_QUIC_REFUSED_STREAM")); +} + +TEST_F(EnvoyQuicServerSessionTest, ResetStream) { + installReadFilter(); + + Http::MockRequestDecoder request_decoder; + Http::MockStreamCallbacks stream_callbacks; + EXPECT_CALL(request_decoder, accessLogHandlers()); + auto stream1 = + dynamic_cast(createNewStream(request_decoder, stream_callbacks)); + EXPECT_CALL(stream_callbacks, onResetStream(Http::StreamResetReason::LocalReset, _)); + EXPECT_CALL(*quic_connection_, SendControlFrame(_)); + stream1->resetStream(Http::StreamResetReason::LocalReset); + EXPECT_EQ(1U, TestUtility::findCounter( + listener_config_.listenerScope().store(), + "http3.downstream.tx.quic_reset_stream_error_code_QUIC_STREAM_REQUEST_REJECTED") + ->value()); + EXPECT_EQ(nullptr, + TestUtility::findCounter( + listener_config_.listenerScope().store(), + "http3.downstream.rx.quic_reset_stream_error_code_QUIC_STREAM_REQUEST_REJECTED")); } TEST_F(EnvoyQuicServerSessionTest, ConnectionClose) { diff --git a/test/common/quic/envoy_quic_server_stream_test.cc b/test/common/quic/envoy_quic_server_stream_test.cc index f8f02758f95d..a1958f3afa2d 100644 --- a/test/common/quic/envoy_quic_server_stream_test.cc +++ b/test/common/quic/envoy_quic_server_stream_test.cc @@ -50,8 +50,10 @@ class EnvoyQuicServerStreamTest : public testing::Test { quic_connection_(connection_helper_, alarm_factory_, writer_, quic::ParsedQuicVersionVector{quic_version_}, *listener_config_.socket_, connection_id_generator_), + quic_stat_names_(listener_config_.listenerScope().symbolTable()), quic_session_(quic_config_, {quic_version_}, &quic_connection_, *dispatcher_, - quic_config_.GetInitialStreamFlowControlWindowToSend() * 2), + quic_config_.GetInitialStreamFlowControlWindowToSend() * 2, quic_stat_names_, + listener_config_.listenerScope()), stats_( {ALL_HTTP3_CODEC_STATS(POOL_COUNTER_PREFIX(listener_config_.listenerScope(), "http3."), POOL_GAUGE_PREFIX(listener_config_.listenerScope(), "http3."))}), @@ -222,6 +224,7 @@ class EnvoyQuicServerStreamTest : public testing::Test { quic::DeterministicConnectionIdGenerator connection_id_generator_{ quic::kQuicDefaultConnectionIdLength}; testing::NiceMock quic_connection_; + Envoy::Quic::QuicStatNames quic_stat_names_; MockEnvoyQuicSession quic_session_; quic::QuicStreamId stream_id_{kStreamId}; Http::Http3::CodecStats stats_; diff --git a/test/common/quic/quic_filter_manager_connection_impl_test.cc b/test/common/quic/quic_filter_manager_connection_impl_test.cc index 1217c6d69d46..a4ddd7600825 100644 --- a/test/common/quic/quic_filter_manager_connection_impl_test.cc +++ b/test/common/quic/quic_filter_manager_connection_impl_test.cc @@ -16,13 +16,15 @@ class TestQuicFilterManagerConnectionImpl : public QuicFilterManagerConnectionIm TestQuicFilterManagerConnectionImpl(QuicNetworkConnection& connection, const quic::QuicConnectionId& connection_id, Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, - std::shared_ptr&& ssl_info) + std::shared_ptr&& ssl_info, + QuicStatNames& quic_stat_names, Stats::Scope& scope) : QuicFilterManagerConnectionImpl( connection, connection_id, dispatcher, send_buffer_limit, std::move(ssl_info), std::make_unique( dispatcher.timeSource(), connection.connectionSocket()->connectionInfoProviderSharedPtr(), - StreamInfo::FilterState::LifeSpan::Connection)) {} + StreamInfo::FilterState::LifeSpan::Connection), + quic_stat_names, scope) {} void dumpState(std::ostream& /*os*/, int /*indent_level = 0*/) const override {} absl::string_view requestedServerName() const override { return {}; } @@ -42,11 +44,12 @@ class QuicFilterManagerConnectionImplTest : public ::testing::Test { public: QuicFilterManagerConnectionImplTest() : socket_(std::make_unique>()), - connection_(std::move(socket_)), + quic_stat_names_(store_.symbolTable()), connection_(std::move(socket_)), quic_session_(new quic::test::MockQuicConnection(&helper_, &alarm_factory_, quic::Perspective::IS_SERVER)), ssl_info_(std::make_shared(quic_session_)), - impl_(connection_, connection_id_, dispatcher_, send_buffer_limit_, std::move(ssl_info_)) {} + impl_(connection_, connection_id_, dispatcher_, send_buffer_limit_, std::move(ssl_info_), + quic_stat_names_, *store_.rootScope()) {} protected: std::unique_ptr> socket_; @@ -55,6 +58,8 @@ class QuicFilterManagerConnectionImplTest : public ::testing::Test { uint32_t send_buffer_limit_ = 0; quic::test::MockQuicConnectionHelper helper_; quic::test::MockAlarmFactory alarm_factory_; + Stats::IsolatedStoreImpl store_; + QuicStatNames quic_stat_names_; QuicNetworkConnection connection_; quic::test::MockQuicSession quic_session_; std::shared_ptr ssl_info_; diff --git a/test/common/quic/test_utils.h b/test/common/quic/test_utils.h index 38f73504af8c..cc94aff40c5a 100644 --- a/test/common/quic/test_utils.h +++ b/test/common/quic/test_utils.h @@ -97,14 +97,16 @@ class MockEnvoyQuicSession : public quic::QuicSpdySession, public QuicFilterMana MockEnvoyQuicSession(const quic::QuicConfig& config, const quic::ParsedQuicVersionVector& supported_versions, EnvoyQuicServerConnection* connection, Event::Dispatcher& dispatcher, - uint32_t send_buffer_limit) + uint32_t send_buffer_limit, QuicStatNames& quic_stat_names, + Stats::Scope& scope) : quic::QuicSpdySession(connection, /*visitor=*/nullptr, config, supported_versions), QuicFilterManagerConnectionImpl( *connection, connection->connection_id(), dispatcher, send_buffer_limit, {nullptr}, std::make_unique( dispatcher.timeSource(), connection->connectionSocket()->connectionInfoProviderSharedPtr(), - StreamInfo::FilterState::LifeSpan::Connection)), + StreamInfo::FilterState::LifeSpan::Connection), + quic_stat_names, scope), crypto_stream_(std::make_unique(this)) {} void Initialize() override { @@ -275,7 +277,8 @@ std::string spdyHeaderToHttp3StreamPayload(const spdy::Http2HeaderBlock& header) quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate; quic::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; auto qpack_encoder = std::make_unique(&decoder_stream_error_delegate, - quic::HuffmanEncoding::kEnabled); + quic::HuffmanEncoding::kEnabled, + quic::CookieCrumbling::kEnabled); qpack_encoder->set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate); // QpackEncoder does not use the dynamic table by default, // therefore the value of |stream_id| does not matter. diff --git a/test/common/router/config_impl_test.cc b/test/common/router/config_impl_test.cc index b9679737b71b..8cc2795e4613 100644 --- a/test/common/router/config_impl_test.cc +++ b/test/common/router/config_impl_test.cc @@ -6305,21 +6305,60 @@ TEST_F(RouteMatcherTest, WeightedClusters) { { Http::TestRequestHeaderMapImpl headers = genHeaders("www3.lyft.com", "/foo", "GET"); EXPECT_CALL(runtime.snapshot_, featureEnabled("www3", 100, _)).WillRepeatedly(Return(true)); + // new total weight will be 140 EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster1", 30)) .WillRepeatedly(Return(10)); - - // We return an invalid value here, one that is greater than 100 - // Expect any random value > 10 to always land in cluster2. EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster2", 30)) .WillRepeatedly(Return(120)); EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster3", 40)) .WillRepeatedly(Return(10)); - EXPECT_EQ("cluster1", config.route(headers, 1005)->routeEntry()->clusterName()); + // 1005 % total_weight == 25 + EXPECT_EQ("cluster2", config.route(headers, 1005)->routeEntry()->clusterName()); EXPECT_EQ("cluster2", config.route(headers, 82)->routeEntry()->clusterName()); EXPECT_EQ("cluster2", config.route(headers, 92)->routeEntry()->clusterName()); } + // Weighted Cluster with runtime values under total weight + // Makes sure new total weight is taken into account + // if total_weight is not recomputed, it will raise "unexpected" error + { + Http::TestRequestHeaderMapImpl headers = genHeaders("www3.lyft.com", "/foo", "GET"); + EXPECT_CALL(runtime.snapshot_, featureEnabled("www3", 100, _)).WillRepeatedly(Return(true)); + // new total weight will be 6 + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster1", 30)) + .WillRepeatedly(Return(1)); + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster2", 30)) + .WillRepeatedly(Return(2)); + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster3", 40)) + .WillRepeatedly(Return(3)); + + // 1005 % total_weight == 3 + EXPECT_EQ("cluster3", config.route(headers, 1005)->routeEntry()->clusterName()); + EXPECT_EQ("cluster3", config.route(headers, 82)->routeEntry()->clusterName()); + EXPECT_EQ("cluster2", config.route(headers, 92)->routeEntry()->clusterName()); + } + + // Total weight is set to zero + { + Http::TestRequestHeaderMapImpl headers = genHeaders("www3.lyft.com", "/foo", "GET"); + EXPECT_CALL(runtime.snapshot_, featureEnabled("www3", 100, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster1", 30)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster2", 30)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(runtime.snapshot_, getInteger("www3_weights.cluster3", 40)) + .WillRepeatedly(Return(0)); + +#if defined(NDEBUG) + // sum of weight returns nullptr + EXPECT_EQ(nullptr, config.route(headers, 42)); +#else + // in debug mode, it aborts + EXPECT_DEATH(config.route(headers, 42), "Sum of weight cannot be zero"); +#endif + } + // Weighted Cluster with runtime values, total weight = 10000 { Http::TestRequestHeaderMapImpl headers = genHeaders("www4.lyft.com", "/foo", "GET"); diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 1ccd9ef87620..ecc13f1b1e24 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -12,6 +12,7 @@ #include "envoy/type/v3/percent.pb.h" #include "source/common/buffer/buffer_impl.h" +#include "source/common/common/base64.h" #include "source/common/common/empty_string.h" #include "source/common/config/metadata.h" #include "source/common/config/well_known_names.h" @@ -6675,5 +6676,74 @@ TEST_F(RouterTest, OverwriteSchemeWithUpstreamTransportProtocol) { callbacks_.route_->virtual_host_.virtual_cluster_.stats().upstream_rq_total_.value()); } +TEST_F(RouterTest, OrcaLoadReport) { + EXPECT_CALL(callbacks_.route_->route_entry_, timeout()) + .WillOnce(Return(std::chrono::milliseconds(0))); + EXPECT_CALL(callbacks_.dispatcher_, createTimer_(_)).Times(0); + + NiceMock encoder; + Http::ResponseDecoder* response_decoder = nullptr; + expectNewStreamWithImmediateEncoder(encoder, &response_decoder, Http::Protocol::Http10); + + Http::TestRequestHeaderMapImpl headers; + HttpTestUtility::addDefaultHeaders(headers); + router_->decodeHeaders(headers, true); + + // Create LRS endpoint metric reporting config with three metrics. + Envoy::Orca::LrsReportMetricNames metric_names; + metric_names.push_back("cpu_utilization"); + metric_names.push_back("named_metrics.good"); + metric_names.push_back("named_metrics.not-in-report"); + ON_CALL(*cm_.thread_local_cluster_.cluster_.info_, lrsReportMetricNames()) + .WillByDefault(Return(makeOptRef(metric_names))); + // Send three metrics, one of which is not in the config. + xds::data::orca::v3::OrcaLoadReport orca_load_report; + orca_load_report.set_cpu_utilization(0.5); + orca_load_report.mutable_named_metrics()->insert({"not-in-config", 0.1}); + orca_load_report.mutable_named_metrics()->insert({"good", 0.7}); + std::string proto_string = TestUtility::getProtobufBinaryStringFromMessage(orca_load_report); + std::string orca_load_report_header_bin = + Envoy::Base64::encode(proto_string.c_str(), proto_string.length()); + Http::ResponseHeaderMapPtr response_headers(new Http::TestResponseHeaderMapImpl{ + {":status", "200"}, {"endpoint-load-metrics-bin", orca_load_report_header_bin}}); + response_decoder->decodeHeaders(std::move(response_headers), true); + auto load_metric_stats_map = + cm_.thread_local_cluster_.conn_pool_.host_->loadMetricStats().latch(); + ASSERT_NE(load_metric_stats_map, nullptr); + EXPECT_EQ(load_metric_stats_map->size(), 2); + EXPECT_EQ(load_metric_stats_map->at("cpu_utilization").total_metric_value, 0.5); + EXPECT_EQ(load_metric_stats_map->at("cpu_utilization").num_requests_with_metric, 1); + EXPECT_EQ(load_metric_stats_map->at("named_metrics.good").total_metric_value, 0.7); + EXPECT_EQ(load_metric_stats_map->at("named_metrics.good").num_requests_with_metric, 1); +} + +TEST_F(RouterTest, OrcaLoadReport_NoConfiguredMetricNames) { + EXPECT_CALL(callbacks_.route_->route_entry_, timeout()) + .WillOnce(Return(std::chrono::milliseconds(0))); + EXPECT_CALL(callbacks_.dispatcher_, createTimer_(_)).Times(0); + + NiceMock encoder; + Http::ResponseDecoder* response_decoder = nullptr; + expectNewStreamWithImmediateEncoder(encoder, &response_decoder, Http::Protocol::Http10); + + Http::TestRequestHeaderMapImpl headers; + HttpTestUtility::addDefaultHeaders(headers); + router_->decodeHeaders(headers, true); + + // Verify that no load metric stats are added when there are no configured metric names. + xds::data::orca::v3::OrcaLoadReport orca_load_report; + orca_load_report.set_cpu_utilization(0.5); + orca_load_report.mutable_named_metrics()->insert({"good", 0.7}); + std::string proto_string = TestUtility::getProtobufBinaryStringFromMessage(orca_load_report); + std::string orca_load_report_header_bin = + Envoy::Base64::encode(proto_string.c_str(), proto_string.length()); + Http::ResponseHeaderMapPtr response_headers(new Http::TestResponseHeaderMapImpl{ + {":status", "200"}, {"endpoint-load-metrics-bin", orca_load_report_header_bin}}); + response_decoder->decodeHeaders(std::move(response_headers), true); + auto load_metric_stats_map = + cm_.thread_local_cluster_.conn_pool_.host_->loadMetricStats().latch(); + ASSERT_EQ(load_metric_stats_map, nullptr); +} + } // namespace Router } // namespace Envoy diff --git a/test/common/stats/tag_extractor_impl_test.cc b/test/common/stats/tag_extractor_impl_test.cc index 6bb2e8443b1e..ab408b1aa9f4 100644 --- a/test/common/stats/tag_extractor_impl_test.cc +++ b/test/common/stats/tag_extractor_impl_test.cc @@ -405,6 +405,20 @@ TEST(TagExtractorTest, DefaultTagExtractors) { regex_tester.testRegex("http.rds_connection_manager.rds.agg/route_config.1-23.update_success", "http.rds.update_success", {rds_hcm, rds_route_config}); + // SRDS. + Tag scoped_rds_hcm; + + scoped_rds_hcm.name_ = tag_names.HTTP_CONN_MANAGER_PREFIX; + scoped_rds_hcm.value_ = "scoped_rds_connection_manager"; + + Tag scoped_rds_route_config; + scoped_rds_route_config.name_ = tag_names.SCOPED_RDS_CONFIG; + scoped_rds_route_config.value_ = "scoped_route_config.123"; + + regex_tester.testRegex( + "http.scoped_rds_connection_manager.scoped_rds.scoped_route_config.123.update_success", + "http.scoped_rds.update_success", {scoped_rds_hcm, scoped_rds_route_config}); + // Listener manager worker id Tag worker_id; worker_id.name_ = tag_names.WORKER_ID; diff --git a/test/common/tcp/async_tcp_client_impl_test.cc b/test/common/tcp/async_tcp_client_impl_test.cc index f185545a1223..409808bdfde7 100644 --- a/test/common/tcp/async_tcp_client_impl_test.cc +++ b/test/common/tcp/async_tcp_client_impl_test.cc @@ -18,6 +18,15 @@ using testing::Return; namespace Envoy { namespace Tcp { +class CustomMockClientConnection : public Network::MockClientConnection { +public: + ~CustomMockClientConnection() { + if (state_ != Connection::State::Closed) { + raiseEvent(Network::ConnectionEvent::LocalClose); + } + }; +}; + class AsyncTcpClientImplTest : public Event::TestUsingSimulatedTime, public testing::Test { public: AsyncTcpClientImplTest() = default; @@ -32,7 +41,7 @@ class AsyncTcpClientImplTest : public Event::TestUsingSimulatedTime, public test } void expectCreateConnection(bool trigger_connected = true) { - connection_ = new NiceMock(); + connection_ = new NiceMock(); Upstream::MockHost::MockCreateConnectionData conn_info; connection_->streamInfo().setAttemptCount(1); conn_info.connection_ = connection_; @@ -59,7 +68,7 @@ class AsyncTcpClientImplTest : public Event::TestUsingSimulatedTime, public test NiceMock* connect_timer_; NiceMock dispatcher_; NiceMock cluster_manager_; - Network::MockClientConnection* connection_{}; + CustomMockClientConnection* connection_{}; NiceMock callbacks_; }; diff --git a/test/common/tls/ssl_socket_test.cc b/test/common/tls/ssl_socket_test.cc index 4ee59996b4d9..ba1ca0b65598 100644 --- a/test/common/tls/ssl_socket_test.cc +++ b/test/common/tls/ssl_socket_test.cc @@ -171,6 +171,12 @@ class TestUtilOptions : public TestUtilOptionsBase { const std::string& expectedSha256Digest() const { return expected_sha256_digest_; } + TestUtilOptions& setExpectedSha256Digests(std::vector& expected_sha256_digests) { + expected_sha256_digests_ = expected_sha256_digests; + return *this; + } + const std::vector expectedSha256Digests() const { return expected_sha256_digests_; } + TestUtilOptions& setExpectedSha1Digest(const std::string& expected_sha1_digest) { expected_sha1_digest_ = expected_sha1_digest; return *this; @@ -178,6 +184,13 @@ class TestUtilOptions : public TestUtilOptionsBase { const std::string& expectedSha1Digest() const { return expected_sha1_digest_; } + TestUtilOptions& setExpectedSha1Digests(std::vector& expected_sha1_digests) { + expected_sha1_digests_ = expected_sha1_digests; + return *this; + } + + const std::vector expectedSha1Digests() const { return expected_sha1_digests_; } + TestUtilOptions& setExpectedLocalUri(const std::string& expected_local_uri) { expected_local_uri_ = {expected_local_uri}; return *this; @@ -192,6 +205,13 @@ class TestUtilOptions : public TestUtilOptionsBase { const std::string& expectedSerialNumber() const { return expected_serial_number_; } + TestUtilOptions& setExpectedSerialNumbers(std::vector& expected_serial_numbers) { + expected_serial_numbers_ = expected_serial_numbers; + return *this; + } + + const std::vector expectedSerialNumbers() const { return expected_serial_numbers_; } + TestUtilOptions& setExpectedPeerIssuer(const std::string& expected_peer_issuer) { expected_peer_issuer_ = expected_peer_issuer; return *this; @@ -313,9 +333,12 @@ class TestUtilOptions : public TestUtilOptionsBase { NiceMock runtime_; Network::ConnectionEvent expected_server_close_event_{Network::ConnectionEvent::RemoteClose}; std::string expected_sha256_digest_; + std::vector expected_sha256_digests_; std::string expected_sha1_digest_; + std::vector expected_sha1_digests_; std::vector expected_local_uri_; std::string expected_serial_number_; + std::vector expected_serial_numbers_; std::string expected_peer_issuer_; std::string expected_peer_subject_; std::string expected_local_subject_; @@ -442,6 +465,13 @@ void testUtil(const TestUtilOptions& options) { EXPECT_EQ(options.expectedSha256Digest(), server_connection->ssl()->sha256PeerCertificateDigest()); } + if (!options.expectedSha256Digests().empty()) { + // Assert twice to ensure a cached value is returned and still valid. + EXPECT_EQ(options.expectedSha256Digests(), + server_connection->ssl()->sha256PeerCertificateChainDigests()); + EXPECT_EQ(options.expectedSha256Digests(), + server_connection->ssl()->sha256PeerCertificateChainDigests()); + } if (!options.expectedSha1Digest().empty()) { // Assert twice to ensure a cached value is returned and still valid. EXPECT_EQ(options.expectedSha1Digest(), @@ -449,6 +479,13 @@ void testUtil(const TestUtilOptions& options) { EXPECT_EQ(options.expectedSha1Digest(), server_connection->ssl()->sha1PeerCertificateDigest()); } + if (!options.expectedSha1Digests().empty()) { + // Assert twice to ensure a cached value is returned and still valid. + EXPECT_EQ(options.expectedSha1Digests(), + server_connection->ssl()->sha1PeerCertificateChainDigests()); + EXPECT_EQ(options.expectedSha1Digests(), + server_connection->ssl()->sha1PeerCertificateChainDigests()); + } // Assert twice to ensure a cached value is returned and still valid. EXPECT_EQ(options.expectedClientCertUri(), server_connection->ssl()->uriSanPeerCertificate()); EXPECT_EQ(options.expectedClientCertUri(), server_connection->ssl()->uriSanPeerCertificate()); @@ -458,18 +495,34 @@ void testUtil(const TestUtilOptions& options) { EXPECT_EQ(options.expectedLocalUri(), server_connection->ssl()->uriSanLocalCertificate()); EXPECT_EQ(options.expectedLocalUri(), server_connection->ssl()->uriSanLocalCertificate()); } + + EXPECT_EQ(options.expectedSerialNumber(), + server_connection->ssl()->serialNumberPeerCertificate()); EXPECT_EQ(options.expectedSerialNumber(), server_connection->ssl()->serialNumberPeerCertificate()); + if (!options.expectedSerialNumbers().empty()) { + // Assert twice to ensure a cached value is returned and still valid. + EXPECT_EQ(options.expectedSerialNumbers(), + server_connection->ssl()->serialNumbersPeerCertificates()); + EXPECT_EQ(options.expectedSerialNumbers(), + server_connection->ssl()->serialNumbersPeerCertificates()); + } if (!options.expectedPeerIssuer().empty()) { + // Assert twice to ensure a cached value is returned and still valid. + EXPECT_EQ(options.expectedPeerIssuer(), server_connection->ssl()->issuerPeerCertificate()); EXPECT_EQ(options.expectedPeerIssuer(), server_connection->ssl()->issuerPeerCertificate()); } if (!options.expectedPeerSubject().empty()) { EXPECT_EQ(options.expectedPeerSubject(), server_connection->ssl()->subjectPeerCertificate()); + EXPECT_EQ(options.expectedPeerSubject(), + server_connection->ssl()->subjectPeerCertificate()); } if (!options.expectedLocalSubject().empty()) { EXPECT_EQ(options.expectedLocalSubject(), server_connection->ssl()->subjectLocalCertificate()); + EXPECT_EQ(options.expectedLocalSubject(), + server_connection->ssl()->subjectLocalCertificate()); } if (!options.expectedPeerCert().empty()) { std::string urlencoded = absl::StrReplaceAll( @@ -817,6 +870,8 @@ void testUtilV2(const TestUtilOptionsV2& options) { if (!options.expectedALPNProtocol().empty()) { EXPECT_EQ(options.expectedALPNProtocol(), client_connection->nextProtocol()); } + // Assert twice to ensure a cached value is returned and still valid. + EXPECT_EQ(options.expectedClientCertUri(), server_connection->ssl()->uriSanPeerCertificate()); EXPECT_EQ(options.expectedClientCertUri(), server_connection->ssl()->uriSanPeerCertificate()); EXPECT_EQ(options.expectedClientCertIpSans(), server_connection->ssl()->ipSansPeerCertificate()); @@ -1098,6 +1153,63 @@ TEST_P(SslSocketTest, GetCertDigestInvalidFiles) { "")); } +TEST_P(SslSocketTest, GetCertDigests) { + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/common/tls/test_data/no_san_chain.pem" + private_key: + filename: "{{ test_rundir }}/test/common/tls/test_data/no_san_key.pem" +)EOF"; + + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/common/tls/test_data/no_san_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/tls/test_data/no_san_key.pem" + validation_context: + trusted_ca: + filename: "{{ test_rundir }}/test/common/tls/test_data/ca_cert.pem" +)EOF"; + + TestUtilOptions test_options(client_ctx_yaml, server_ctx_yaml, true, version_); + std::vector sha256Digests = absl::StrSplit(TEST_NO_SAN_CERT_CHAIN_256_HASHES, ','); + std::vector sha1Digests = absl::StrSplit(TEST_NO_SAN_CERT_CHAIN_1_HASHES, ','); + std::vector serialNumbers = absl::StrSplit(TEST_NO_SAN_CERT_CHAIN_SERIALS, ','); + testUtil(test_options.setExpectedSha256Digests(sha256Digests) + .setExpectedSha1Digests(sha1Digests) + .setExpectedSerialNumber(TEST_NO_SAN_CERT_SERIAL) // test checks first serial # + .setExpectedSerialNumbers(serialNumbers)); +} + +TEST_P(SslSocketTest, GetCertDigestsInvalidFiles) { + const std::string client_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: +)EOF"; + + const std::string server_ctx_yaml = R"EOF( + common_tls_context: + tls_certificates: + certificate_chain: + filename: "{{ test_rundir }}/test/common/tls/test_data/san_dns_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/tls/test_data/san_dns_key.pem" + validation_context: + trusted_ca: + filename: "{{ test_rundir }}/test/common/tls/test_data/ca_cert.pem" +)EOF"; + + TestUtilOptions test_options(client_ctx_yaml, server_ctx_yaml, true, version_); + std::vector emptyStringVec; + testUtil(test_options.setExpectedSha256Digests(emptyStringVec) + .setExpectedSha1Digests(emptyStringVec) + .setExpectedSerialNumbers(emptyStringVec)); +} + TEST_P(SslSocketTest, GetCertDigestInline) { envoy::config::listener::v3::Listener listener; envoy::config::listener::v3::FilterChain* filter_chain = listener.add_filter_chains(); diff --git a/test/common/tls/test_data/no_san_cert_info.h b/test/common/tls/test_data/no_san_cert_info.h index 22f671841618..9072c54c5509 100644 --- a/test/common/tls/test_data/no_san_cert_info.h +++ b/test/common/tls/test_data/no_san_cert_info.h @@ -3,8 +3,15 @@ // NOLINT(namespace-envoy) constexpr char TEST_NO_SAN_CERT_256_HASH[] = "1fa3b1626367eda0b93b20cab52a08ace81aeab55245abf29b7920873658ce11"; +constexpr char TEST_NO_SAN_CERT_CHAIN_256_HASHES[] = + "1fa3b1626367eda0b93b20cab52a08ace81aeab55245abf29b7920873658ce11," + "91b048a0941a41740a243a8db4509ba31abdf0c00a1aa9fa36fe2e28d029b22f"; constexpr char TEST_NO_SAN_CERT_1_HASH[] = "c773be7b9f642ceadaa4ac8b8c8417e900435955"; +constexpr char TEST_NO_SAN_CERT_CHAIN_1_HASHES[] = "c773be7b9f642ceadaa4ac8b8c8417e900435955," + "635057edf7e2eabf863ab7fb5748a443aaeffee6"; constexpr char TEST_NO_SAN_CERT_SPKI[] = "eMMC8S2gS0LSZAF9bFmxP4YrI5NeUp/T+UzDKhJEiGA="; constexpr char TEST_NO_SAN_CERT_SERIAL[] = "7c252c75e95aa57a88f1f1c5cc3ff4fa9c5aa4c1"; +constexpr char TEST_NO_SAN_CERT_CHAIN_SERIALS[] = "7c252c75e95aa57a88f1f1c5cc3ff4fa9c5aa4c1," + "7c252c75e95aa57a88f1f1c5cc3ff4fa9c5aa4bf"; constexpr char TEST_NO_SAN_CERT_NOT_BEFORE[] = "Aug 22 07:51:29 2022 GMT"; constexpr char TEST_NO_SAN_CERT_NOT_AFTER[] = "Aug 21 07:51:29 2024 GMT"; diff --git a/test/common/tls/utility_test.cc b/test/common/tls/utility_test.cc index 005ca1fe58ca..7f028922fa31 100644 --- a/test/common/tls/utility_test.cc +++ b/test/common/tls/utility_test.cc @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -209,6 +211,25 @@ TEST(UtilityTest, TestGetX509ErrorInfo) { "verification error"); } +TEST(UtilityTest, TestMapX509Stack) { + bssl::UniquePtr cert_chain = readCertChainFromFile( + TestEnvironment::substitute("{{ test_rundir }}/test/common/tls/test_data/no_san_chain.pem")); + + std::vector expected_subject{ + "CN=Test Server,OU=Lyft Engineering,O=Lyft,L=San " + "Francisco,ST=California,C=US", + "CN=Test Intermediate CA,OU=Lyft Engineering,O=Lyft,L=San Francisco," + "ST=California,C=US"}; + auto func = [](X509& cert) -> std::string { return Utility::getSubjectFromCertificate(cert); }; + EXPECT_EQ(expected_subject, Utility::mapX509Stack(*cert_chain, func)); + + EXPECT_ENVOY_BUG(Utility::mapX509Stack(*sk_X509_new_null(), func), "x509 stack is empty or NULL"); + EXPECT_ENVOY_BUG(Utility::mapX509Stack(*cert_chain, nullptr), "field_extractor is nullptr"); + bssl::UniquePtr fakeCertChain(sk_X509_new_null()); + sk_X509_push(fakeCertChain.get(), nullptr); + EXPECT_EQ(std::vector{""}, Utility::mapX509Stack(*fakeCertChain, func)); +} + } // namespace } // namespace Tls } // namespace TransportSockets diff --git a/test/common/upstream/upstream_impl_test.cc b/test/common/upstream/upstream_impl_test.cc index e8267dbf2843..b0d5217b2bb2 100644 --- a/test/common/upstream/upstream_impl_test.cc +++ b/test/common/upstream/upstream_impl_test.cc @@ -6118,7 +6118,7 @@ TEST_F(ClusterInfoImplTest, FilterChain) { auto cluster = makeCluster(yaml); Http::MockFilterChainManager manager; - Http::EmptyFilterChainOptions options; + const Http::EmptyFilterChainOptions options; EXPECT_FALSE(cluster->info()->createUpgradeFilterChain("foo", nullptr, manager, options)); EXPECT_CALL(manager, applyFilterFactoryCb(_, _)); diff --git a/test/config/BUILD b/test/config/BUILD index e45e7a26cd56..c338643e0709 100644 --- a/test/config/BUILD +++ b/test/config/BUILD @@ -37,6 +37,7 @@ envoy_cc_test_library( "@envoy_api//envoy/extensions/access_loggers/file/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/filters/http/upstream_codec/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/udp/udp_proxy/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/transport_sockets/quic/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/transport_sockets/tls/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/upstreams/http/v3:pkg_cc_proto", diff --git a/test/config/utility.cc b/test/config/utility.cc index 69891e86f60b..668d4f290882 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -1575,6 +1575,21 @@ envoy::config::listener::v3::Filter* ConfigHelper::getFilterFromListener(const s return nullptr; } +envoy::config::listener::v3::ListenerFilter* +ConfigHelper::getListenerFilterFromListener(const std::string& name) { + RELEASE_ASSERT(!finalized_, ""); + if (bootstrap_.mutable_static_resources()->listeners_size() == 0) { + return nullptr; + } + auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0); + for (ssize_t i = 0; i < listener->listener_filters_size(); i++) { + if (listener->mutable_listener_filters(i)->name() == name) { + return listener->mutable_listener_filters(i); + } + } + return nullptr; +} + void ConfigHelper::addNetworkFilter(const std::string& filter_yaml) { RELEASE_ASSERT(!finalized_, ""); auto* filter_chain = @@ -1639,6 +1654,14 @@ void ConfigHelper::storeHttpConnectionManager( "http", hcm); } +bool ConfigHelper::loadUdpProxyFilter(UdpProxyConfig& udp_proxy) { + return loadListenerFilter("udp_proxy", udp_proxy); +} + +void ConfigHelper::storeUdpProxyFilter(const UdpProxyConfig& udp_proxy) { + return storeListenerFilter("udp_proxy", udp_proxy); +} + void ConfigHelper::addConfigModifier(ConfigModifierFunction function) { RELEASE_ASSERT(!finalized_, ""); config_modifiers_.push_back(std::move(function)); @@ -1656,6 +1679,17 @@ void ConfigHelper::addConfigModifier(HttpModifierFunction function) { }); } +void ConfigHelper::addConfigModifier(UdpProxyModifierFunction function) { + addConfigModifier([function, this](envoy::config::bootstrap::v3::Bootstrap&) -> void { + UdpProxyConfig udp_proxy_config; + if (!loadUdpProxyFilter(udp_proxy_config)) { + return; + } + function(udp_proxy_config); + storeUdpProxyFilter(udp_proxy_config); + }); +} + void ConfigHelper::setLds(absl::string_view version_info) { applyConfigModifiers(); diff --git a/test/config/utility.h b/test/config/utility.h index eb34d534bbec..9410d2e84ec7 100644 --- a/test/config/utility.h +++ b/test/config/utility.h @@ -14,6 +14,7 @@ #include "envoy/config/listener/v3/listener_components.pb.h" #include "envoy/config/route/v3/route_components.pb.h" #include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h" +#include "envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.pb.h" #include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h" #include "envoy/extensions/transport_sockets/tls/v3/common.pb.h" #include "envoy/extensions/upstreams/http/v3/http_protocol_options.pb.h" @@ -34,6 +35,8 @@ class ConfigHelper { public: using HttpConnectionManager = envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager; + using UdpProxyConfig = envoy::extensions::filters::udp::udp_proxy::v3::UdpProxyConfig; + struct ServerSslOptions { ServerSslOptions& setAllowExpiredCertificate(bool allow) { allow_expired_certificate_ = allow; @@ -185,6 +188,7 @@ class ConfigHelper { const ServerSslOptions& options); using ConfigModifierFunction = std::function; using HttpModifierFunction = std::function; + using UdpProxyModifierFunction = std::function; // A basic configuration (admin port, cluster_0, no listeners) with no network filters. static std::string baseConfigNoListeners(); @@ -377,6 +381,10 @@ class ConfigHelper { // Modifiers will be applied just before ports are modified in finalize void addConfigModifier(HttpModifierFunction function); + // Allows callers to easily modify the UDP Proxy configuration. + // Modifiers will be applied just before ports are modified in finalize + void addConfigModifier(UdpProxyModifierFunction function); + // Allows callers to easily modify the filter named 'name' from the first filter chain from the // first listener. Modifiers will be applied just before ports are modified in finalize template @@ -462,6 +470,11 @@ class ConfigHelper { // Take the contents of the provided HCM proto and stuff them into the first HCM // struct of the first listener. void storeHttpConnectionManager(const HttpConnectionManager& hcm); + // Load the first UDP Proxy from the first listener into a parsed proto. + bool loadUdpProxyFilter(UdpProxyConfig& udp_proxy); + // Take the contents of the provided UDP Proxy and stuff them into the first HCM + // struct of the first listener. + void storeUdpProxyFilter(const UdpProxyConfig& udp_proxy); private: // Load the first FilterType struct from the first listener into a parsed proto. @@ -484,9 +497,35 @@ class ConfigHelper { filter_config_any->PackFrom(filter); } + // Load the first FilterType struct from the first listener filters into a parsed proto. + template bool loadListenerFilter(const std::string& name, FilterType& filter) { + RELEASE_ASSERT(!finalized_, ""); + auto* filter_config = getListenerFilterFromListener(name); + if (filter_config) { + auto* config = filter_config->mutable_typed_config(); + filter = MessageUtil::anyConvert(*config); + return true; + } + return false; + } + + // Take the contents of the provided FilterType proto and stuff them into the first FilterType + // struct of the first listener. + template + void storeListenerFilter(const std::string& name, const FilterType& filter) { + RELEASE_ASSERT(!finalized_, ""); + auto* filter_config_any = getListenerFilterFromListener(name)->mutable_typed_config(); + + filter_config_any->PackFrom(filter); + } + // Finds the filter named 'name' from the first filter chain from the first listener. envoy::config::listener::v3::Filter* getFilterFromListener(const std::string& name); + // Finds the filter named 'name' from the first listener filter from the first listener. + envoy::config::listener::v3::ListenerFilter* + getListenerFilterFromListener(const std::string& name); + // The bootstrap proto Envoy will start up with. envoy::config::bootstrap::v3::Bootstrap bootstrap_; diff --git a/test/extensions/common/aws/metadata_fetcher_test.cc b/test/extensions/common/aws/metadata_fetcher_test.cc index da4702211d00..32356aa883e1 100644 --- a/test/extensions/common/aws/metadata_fetcher_test.cc +++ b/test/extensions/common/aws/metadata_fetcher_test.cc @@ -77,6 +77,20 @@ MATCHER_P(OptionsHasRetryPolicy, policyMatcher, "") { class MetadataFetcherTest : public testing::Test { public: void setupFetcher() { + + mock_factory_ctx_.server_factory_context_.cluster_manager_.initializeThreadLocalClusters( + {"cluster_name"}); + fetcher_ = MetadataFetcher::create(mock_factory_ctx_.server_factory_context_.cluster_manager_, + "cluster_name"); + EXPECT_TRUE(fetcher_ != nullptr); + } + + void setupFetcherShutDown() { + ON_CALL(mock_factory_ctx_.server_factory_context_.cluster_manager_, getThreadLocalCluster(_)) + .WillByDefault(Return(nullptr)); + ON_CALL(mock_factory_ctx_.server_factory_context_.cluster_manager_, isShutdown()) + .WillByDefault(Return(true)); + mock_factory_ctx_.server_factory_context_.cluster_manager_.initializeThreadLocalClusters( {"cluster_name"}); fetcher_ = MetadataFetcher::create(mock_factory_ctx_.server_factory_context_.cluster_manager_, @@ -103,6 +117,18 @@ TEST_F(MetadataFetcherTest, TestGetSuccess) { fetcher_->fetch(message, parent_span_, receiver); } +TEST_F(MetadataFetcherTest, TestClusterShutdown) { + // Setup + setupFetcherShutDown(); + Http::RequestMessageImpl message; + MockMetadataReceiver receiver; + EXPECT_CALL(receiver, onMetadataSuccess(_)).Times(0); + EXPECT_CALL(receiver, onMetadataError(_)).Times(0); + + // Act + fetcher_->fetch(message, parent_span_, receiver); +} + TEST_F(MetadataFetcherTest, TestRequestMatchAndSpanPassedDown) { // Setup setupFetcher(); diff --git a/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc b/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc index dae49294ef84..85e4e72a53aa 100644 --- a/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc +++ b/test/extensions/common/dynamic_forward_proxy/dns_cache_impl_test.cc @@ -135,19 +135,7 @@ void verifyCaresDnsConfigAndUnpack( typed_dns_resolver_config.typed_config().UnpackTo(&cares); } -class DnsCacheImplPreresolveTest : public DnsCacheImplTest, - public testing::WithParamInterface { -public: - bool normalizeDfpHost() { return GetParam(); } -}; - -INSTANTIATE_TEST_SUITE_P(DnsCachePreresolveNormalizedDfpHost, DnsCacheImplPreresolveTest, - testing::Bool()); - -TEST_P(DnsCacheImplPreresolveTest, PreresolveSuccess) { - scoped_runtime_.mergeValues({{"envoy.reloadable_features.normalize_host_for_preresolve_dfp_dns", - absl::StrCat(normalizeDfpHost())}}); - +TEST_F(DnsCacheImplTest, PreresolveSuccess) { Network::DnsResolver::ResolveCb resolve_cb; std::string host = "bar.baz.com"; uint32_t port = 443; @@ -162,7 +150,7 @@ TEST_P(DnsCacheImplPreresolveTest, PreresolveSuccess) { DnsHostInfoEquals("10.0.0.1:443", "bar.baz.com", false), Network::DnsResolver::ResolutionStatus::Success)); - initialize({{normalizeDfpHost() ? host : authority, port}} /* preresolve_hostnames */); + initialize({{host, port}} /* preresolve_hostnames */); resolve_cb(Network::DnsResolver::ResolutionStatus::Success, "", TestUtility::makeDnsResponse({"10.0.0.1"})); @@ -170,21 +158,19 @@ TEST_P(DnsCacheImplPreresolveTest, PreresolveSuccess) { 1 /* added */, 0 /* removed */, 1 /* num hosts */); MockLoadDnsCacheEntryCallbacks callbacks; - if (normalizeDfpHost()) { - // Retrieve with the hostname and port in the "host". - auto result = dns_cache_->loadDnsCacheEntry(authority, port, false, callbacks); - EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::InCache, result.status_); - EXPECT_EQ(result.handle_, nullptr); - EXPECT_NE(absl::nullopt, result.host_info_); - } + // Retrieve with the hostname and port in the "host". + auto result = dns_cache_->loadDnsCacheEntry(authority, port, false, callbacks); + EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::InCache, result.status_); + EXPECT_EQ(result.handle_, nullptr); + EXPECT_NE(absl::nullopt, result.host_info_); // Retrieve with the hostname only in the "host". - auto result = dns_cache_->loadDnsCacheEntry(host, port, false, callbacks); + result = dns_cache_->loadDnsCacheEntry(host, port, false, callbacks); EXPECT_EQ(DnsCache::LoadDnsCacheEntryStatus::InCache, result.status_); EXPECT_EQ(result.handle_, nullptr); EXPECT_NE(absl::nullopt, result.host_info_); } -TEST_P(DnsCacheImplPreresolveTest, PreresolveFailure) { +TEST_F(DnsCacheImplTest, PreresolveFailure) { EXPECT_THROW_WITH_MESSAGE( initialize({{"bar.baz.com", 443}} /* preresolve_hostnames */, 0 /* max_hosts */), EnvoyException, diff --git a/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc b/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc index 6e69db824701..383b13a750d6 100644 --- a/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc +++ b/test/extensions/config_subscription/grpc/grpc_mux_failover_test.cc @@ -398,25 +398,43 @@ TEST_F(GrpcMuxFailoverTest, PrimaryOnlyAttemptsAfterPrimaryAvailable) { grpc_mux_failover_->establishNewStream(); } -// Validate that after the failover is available (a response is received), all -// reconnect attempts will be to the failover. -TEST_F(GrpcMuxFailoverTest, FailoverOnlyAttemptsAfterFailoverAvailable) { +// Validate that after the failover is available (a response is received), Envoy +// will try to reconnect to the primary (and then failover), and keep +// alternating between the two. +TEST_F(GrpcMuxFailoverTest, AlternatingPrimaryAndFailoverAttemptsAfterFailoverAvailable) { connectToFailover(); - // Emulate 5 disconnects, and ensure the primary reconnection isn't attempted. + // Emulate a 5 times disconnects. for (int attempt = 0; attempt < 5; ++attempt) { - // Emulate a failover source failure that will not result in an attempt to - // connect to the primary. It should not close the failover stream (so - // the retry mechanism will kick in). - EXPECT_CALL(failover_stream_, closeStream()).Times(0); - EXPECT_CALL(grpc_mux_callbacks_, onEstablishmentFailure()); - EXPECT_CALL(primary_stream_, establishNewStream()).Times(0); - failover_callbacks_->onEstablishmentFailure(); + if (attempt % 2 == 0) { + // Emulate a failover source failure that will result in an attempt to + // connect to the primary. It should close the failover stream, and + // enable the retry timer. + EXPECT_CALL(failover_stream_, closeStream()); + EXPECT_CALL(grpc_mux_callbacks_, onEstablishmentFailure()); + EXPECT_CALL(failover_stream_, establishNewStream()).Times(0); + EXPECT_CALL(*timer_, enableTimer(_, _)); + failover_callbacks_->onEstablishmentFailure(); + // Emulate a timer tick, which should try to reconnect to the primary + // stream. + EXPECT_CALL(primary_stream_, establishNewStream()); + timer_cb_(); + } else { + // Emulate a primary source failure that will result in an attempt to + // connect to the failover. It should close the primary stream, and + // try to establish the failover stream. + EXPECT_CALL(primary_stream_, closeStream()); + EXPECT_CALL(grpc_mux_callbacks_, onEstablishmentFailure()); + EXPECT_CALL(primary_stream_, establishNewStream()).Times(0); + EXPECT_CALL(failover_stream_, establishNewStream()); + primary_callbacks_->onEstablishmentFailure(); + } } - // Emulate a call to establishNewStream(). - EXPECT_CALL(primary_stream_, establishNewStream()).Times(0); - EXPECT_CALL(failover_stream_, establishNewStream()); + // Last attempt ended with failing to establish a failover stream, + // emulate a successful primary stream. + EXPECT_CALL(failover_stream_, establishNewStream()).Times(0); + EXPECT_CALL(primary_stream_, establishNewStream()); grpc_mux_failover_->establishNewStream(); } @@ -603,6 +621,29 @@ TEST_F(GrpcMuxFailoverTest, OnWriteableConnectedToPrimaryInvoked) { primary_callbacks_->onWriteable(); } +// Validates that when connected to primary, a subsequent call to establishNewStream +// will not try to recreate the stream. +TEST_F(GrpcMuxFailoverTest, NoRecreateStreamWhenConnectedToPrimary) { + // Validate connected to primary. + { + connectToPrimary(); + EXPECT_CALL(primary_stream_, establishNewStream()).Times(0); + EXPECT_CALL(failover_stream_, establishNewStream()).Times(0); + grpc_mux_failover_->establishNewStream(); + } +} + +// Validates that when connected to failover, a subsequent call to establishNewStream +// will not try to recreate the stream. +TEST_F(GrpcMuxFailoverTest, NoRecreateStreamWhenConnectedToFailover) { + // Validate connected to failover. + { + connectToFailover(); + EXPECT_CALL(primary_stream_, establishNewStream()).Times(0); + EXPECT_CALL(failover_stream_, establishNewStream()).Times(0); + grpc_mux_failover_->establishNewStream(); + } +} } // namespace } // namespace Config } // namespace Envoy diff --git a/test/extensions/config_subscription/grpc/xds_failover_integration_test.cc b/test/extensions/config_subscription/grpc/xds_failover_integration_test.cc index d48a51b16980..93be6621f445 100644 --- a/test/extensions/config_subscription/grpc/xds_failover_integration_test.cc +++ b/test/extensions/config_subscription/grpc/xds_failover_integration_test.cc @@ -183,6 +183,14 @@ class XdsFailoverAdsIntegrationTest : public AdsDeltaSotwIntegrationSubStatePara RELEASE_ASSERT(result, result.message()); } + // Waits for a failover source connected and immediately disconnects. + void failoverConnectionFailure() { + AssertionResult result = xds_upstream_->waitForHttpConnection(*dispatcher_, xds_connection_); + RELEASE_ASSERT(result, result.message()); + result = xds_connection_->close(); + RELEASE_ASSERT(result, result.message()); + } + envoy::config::endpoint::v3::ClusterLoadAssignment buildClusterLoadAssignment(const std::string& name) { return ConfigHelper::buildClusterLoadAssignment( @@ -559,8 +567,8 @@ TEST_P(XdsFailoverAdsIntegrationTest, NoFailoverUseAfterPrimaryResponse) { xds_stream_.get())); } -// Validate that once failover answers, primary will not be used, even after disconnecting. -TEST_P(XdsFailoverAdsIntegrationTest, NoPrimaryUseAfterFailoverResponse) { +// Validate that once failover responds, and then disconnects, primary will be attempted. +TEST_P(XdsFailoverAdsIntegrationTest, PrimaryUseAfterFailoverResponseAndDisconnect) { // These tests are not executed with GoogleGrpc because they are flaky due to // the large timeout values for retries. SKIP_IF_GRPC_CLIENT(Grpc::ClientType::GoogleGrpc); @@ -579,9 +587,9 @@ TEST_P(XdsFailoverAdsIntegrationTest, NoPrimaryUseAfterFailoverResponse) { ASSERT_TRUE(xds_connection_->waitForDisconnect()); // The CDS request fails when the primary disconnects. After that fetch the config // dump to ensure that the retry timer kicks in. - waitForPrimaryXdsRetryTimer(); // Expect another connection attempt to the primary. Reject the stream (gRPC failure) immediately. // As this is a 2nd consecutive failure, it will trigger failover. + waitForPrimaryXdsRetryTimer(); primaryConnectionFailure(); ASSERT_TRUE(xds_connection_->waitForDisconnect()); @@ -601,68 +609,285 @@ TEST_P(XdsFailoverAdsIntegrationTest, NoPrimaryUseAfterFailoverResponse) { Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); sendDiscoveryResponse( - CdsTypeUrl, {ConfigHelper::buildCluster("cluster_0")}, - {ConfigHelper::buildCluster("cluster_0")}, {}, "1", {}, failover_xds_stream_.get()); + CdsTypeUrl, {ConfigHelper::buildCluster("failover_cluster_0")}, + {ConfigHelper::buildCluster("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + // Wait for an EDS request, and send its response. test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); - test_server_->waitForGaugeEq("cluster.cluster_0.warming_state", 1); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 1); + EXPECT_TRUE(compareDiscoveryRequest( + EdsTypeUrl, "", {"failover_cluster_0"}, {"failover_cluster_0"}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); + sendDiscoveryResponse( + EdsTypeUrl, {buildClusterLoadAssignment("failover_cluster_0")}, + {buildClusterLoadAssignment("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 0); + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "failover1", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); - // Envoy has received a CDS response, it means the primary is available. - // Now disconnect the primary. + // Envoy has received CDS and EDS responses, it means the failover is available. + // Now disconnect the failover source. failover_xds_stream_->finishGrpcStream(Grpc::Status::Internal); - // CDS was successful, but EDS will fail. After that add a notification to the + // CDS and EDS were successful, but LDS will fail. After that add a notification to the // main thread to ensure that the retry timer kicks in. - test_server_->waitForCounterGe("cluster.cluster_0.update_failure", 1); + test_server_->waitForCounterGe("listener_manager.lds.update_failure", 1); absl::Notification notification; test_server_->server().dispatcher().post([&]() { notification.Notify(); }); notification.WaitForNotification(); timeSystem().advanceTimeWait(std::chrono::milliseconds(1000)); - // In this case (received a response), both EnvoyGrpc and GoogleGrpc keep the connection open. + // The failover disconnected, so the next step is trying to connect to the + // primary. First ensure that the failover isn't being attempted, and then let + // the connection to the primary succeed. + EXPECT_FALSE(failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_, + std::chrono::seconds(5))); + EXPECT_TRUE(xds_upstream_->waitForHttpConnection(*dispatcher_, xds_connection_)); + + // Allow receiving config from the primary. + result = xds_connection_->waitForNewStream(*dispatcher_, xds_stream_); + xds_stream_->startGrpcStream(); + + // Ensure basic flow with primary works. Validate that the + // initial_resource_versions for delta-xDS is empty. + // TODO(adisuissa): ensure initial_resource_versions is empty, once this is supported. + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "", {}, {}, {}, true, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + xds_stream_.get())); + EXPECT_TRUE( + compareDiscoveryRequest(EdsTypeUrl, "", {"failover_cluster_0"}, {"failover_cluster_0"}, {}, + false, Grpc::Status::WellKnownGrpcStatus::Ok, "", xds_stream_.get())); + EXPECT_TRUE(compareDiscoveryRequest(LdsTypeUrl, "", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + xds_stream_.get())); + sendDiscoveryResponse( + CdsTypeUrl, {ConfigHelper::buildCluster("primary_cluster_0")}, + {ConfigHelper::buildCluster("primary_cluster_0")}, {}, "primary1", {}, xds_stream_.get()); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + test_server_->waitForGaugeEq("cluster.primary_cluster_0.warming_state", 1); + + // Expect an updated failover EDS request. + EXPECT_TRUE(compareDiscoveryRequest(EdsTypeUrl, "", {"primary_cluster_0"}, {"primary_cluster_0"}, + {}, false, Grpc::Status::WellKnownGrpcStatus::Ok, "", + xds_stream_.get())); +} + +// Validates that if failover is used, and then disconnected, and the primary +// still doesn't respond, failover will be attempted with the correct +// initial_resource_versions. +TEST_P(XdsFailoverAdsIntegrationTest, FailoverUseAfterFailoverResponseAndDisconnect) { + // These tests are not executed with GoogleGrpc because they are flaky due to + // the large timeout values for retries. + SKIP_IF_GRPC_CLIENT(Grpc::ClientType::GoogleGrpc); +#ifdef ENVOY_ENABLE_UHV + // With UHV the finishGrpcStream() isn't detected as invalid frame because of + // no ":status" header, unless "envoy.reloadable_features.enable_universal_header_validator" + // is also enabled. + config_helper_.addRuntimeOverride("envoy.reloadable_features.enable_universal_header_validator", + "true"); +#endif + initialize(); + + // 2 consecutive primary failures. + // Expect a connection to the primary. Reject the connection immediately. + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + // The CDS request fails when the primary disconnects. After that fetch the config + // dump to ensure that the retry timer kicks in. + // Expect another connection attempt to the primary. Reject the stream (gRPC failure) immediately. + // As this is a 2nd consecutive failure, it will trigger failover. + waitForPrimaryXdsRetryTimer(); + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + + // The CDS request fails when the primary disconnects. + test_server_->waitForCounterGe("cluster_manager.cds.update_failure", 2); + + AssertionResult result = + failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_); + RELEASE_ASSERT(result, result.message()); + // Failover is healthy, start the ADS gRPC stream. result = failover_xds_connection_->waitForNewStream(*dispatcher_, failover_xds_stream_); RELEASE_ASSERT(result, result.message()); - // Immediately fail the connection. - failover_xds_stream_->finishGrpcStream(Grpc::Status::Internal); - - // Ensure that Envoy still attempts to connect to the primary, - // and keep disconnecting a few times and validate that the failover - // connection isn't attempted. - for (int i = 1; i < 5; ++i) { - ASSERT_TRUE(failover_xds_connection_->waitForDisconnect()); - // Wait longer due to the fixed 5 seconds failover . - waitForPrimaryXdsRetryTimer(i, 5); - // EnvoyGrpc will disconnect if the gRPC stream is immediately closed (as - // done above). - result = failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_); - RELEASE_ASSERT(result, result.message()); - result = failover_xds_connection_->waitForNewStream(*dispatcher_, failover_xds_stream_); - RELEASE_ASSERT(result, result.message()); - // Immediately fail the connection. - failover_xds_stream_->finishGrpcStream(Grpc::Status::Internal); - } + failover_xds_stream_->startGrpcStream(); - // When EnvoyGrpc is used, no new connection to the primary will be attempted. - EXPECT_FALSE( - xds_upstream_->waitForHttpConnection(*dispatcher_, xds_connection_, std::chrono::seconds(1))); + // Ensure basic flow with failover works. + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "", {}, {}, {}, true, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + sendDiscoveryResponse( + CdsTypeUrl, {ConfigHelper::buildCluster("failover_cluster_0")}, + {ConfigHelper::buildCluster("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + // Wait for an EDS request, and send its response. + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 1); + EXPECT_TRUE(compareDiscoveryRequest( + EdsTypeUrl, "", {"failover_cluster_0"}, {"failover_cluster_0"}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); + sendDiscoveryResponse( + EdsTypeUrl, {buildClusterLoadAssignment("failover_cluster_0")}, + {buildClusterLoadAssignment("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 0); + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "failover1", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + // Envoy has received CDS and EDS responses, it means the failover is available. + // Now disconnect the failover. + failover_xds_stream_->finishGrpcStream(Grpc::Status::Internal); + EXPECT_TRUE(failover_xds_connection_->close()); ASSERT_TRUE(failover_xds_connection_->waitForDisconnect()); - // Wait longer due to the fixed 5 seconds failover . - waitForPrimaryXdsRetryTimer(5, 5); - // Allow a connection to the failover. - // Expect a connection to the failover when using EnvoyGrpc. - // In case GoogleGrpc is used the current connection will be reused (new stream). + // Wait longer due to the fixed 5 seconds failover. + waitForPrimaryXdsRetryTimer(3, 5); + + // The failover disconnected, so the next step is trying to connect to the + // primary source. Disconnect the primary source immediately. + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + + // Expect a connection to the failover source to be attempted. result = failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_); RELEASE_ASSERT(result, result.message()); + + // Failover is healthy, start the ADS gRPC stream. result = failover_xds_connection_->waitForNewStream(*dispatcher_, failover_xds_stream_); + RELEASE_ASSERT(result, result.message()); failover_xds_stream_->startGrpcStream(); - // Validate that just the initial requests are sent to the primary. - EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "1", {}, {}, {}, true, + // Ensure basic flow with primary works. Validate that the + // initial_resource_versions for delta-xDS is empty. + // TODO(adisuissa): ensure initial_resource_versions contains the correct versions. + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "", {}, {}, {}, true, Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); - EXPECT_TRUE(compareDiscoveryRequest(EdsTypeUrl, "", {"cluster_0"}, {"cluster_0"}, {}, false, + EXPECT_TRUE(compareDiscoveryRequest( + EdsTypeUrl, "", {"failover_cluster_0"}, {"failover_cluster_0"}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); + EXPECT_TRUE(compareDiscoveryRequest(LdsTypeUrl, "", {}, {}, {}, false, Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); + sendDiscoveryResponse( + CdsTypeUrl, {ConfigHelper::buildCluster("failover_cluster_1")}, + {ConfigHelper::buildCluster("failover_cluster_1")}, {}, "failover2", {}, + failover_xds_stream_.get()); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + test_server_->waitForGaugeEq("cluster.failover_cluster_1.warming_state", 1); + + // Expect an updated failover EDS request. + EXPECT_TRUE(compareDiscoveryRequest( + EdsTypeUrl, "", {"failover_cluster_1"}, {"failover_cluster_1"}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); +} + +// Validate that once failover responds, and then disconnects, Envoy +// will alternate between the primary and failover sources (multiple times) if +// both are not responding. +TEST_P(XdsFailoverAdsIntegrationTest, + PrimaryAndFailoverAttemptsAfterFailoverResponseAndDisconnect) { + // These tests are not executed with GoogleGrpc because they are flaky due to + // the large timeout values for retries. + SKIP_IF_GRPC_CLIENT(Grpc::ClientType::GoogleGrpc); +#ifdef ENVOY_ENABLE_UHV + // With UHV the finishGrpcStream() isn't detected as invalid frame because of + // no ":status" header, unless "envoy.reloadable_features.enable_universal_header_validator" + // is also enabled. + config_helper_.addRuntimeOverride("envoy.reloadable_features.enable_universal_header_validator", + "true"); +#endif + initialize(); + + // 2 consecutive primary failures. + // Expect a connection to the primary. Reject the connection immediately. + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + // The CDS request fails when the primary disconnects. After that fetch the config + // dump to ensure that the retry timer kicks in. + // Expect another connection attempt to the primary. Reject the stream (gRPC failure) immediately. + // As this is a 2nd consecutive failure, it will trigger failover. + waitForPrimaryXdsRetryTimer(); + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + + // The CDS request fails when the primary disconnects. + test_server_->waitForCounterGe("cluster_manager.cds.update_failure", 2); + + AssertionResult result = + failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_); + RELEASE_ASSERT(result, result.message()); + // Failover is healthy, start the ADS gRPC stream. + result = failover_xds_connection_->waitForNewStream(*dispatcher_, failover_xds_stream_); + RELEASE_ASSERT(result, result.message()); + failover_xds_stream_->startGrpcStream(); + + // Ensure basic flow with failover works. + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "", {}, {}, {}, true, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + sendDiscoveryResponse( + CdsTypeUrl, {ConfigHelper::buildCluster("failover_cluster_0")}, + {ConfigHelper::buildCluster("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + // Wait for an EDS request, and send its response. + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 1); + EXPECT_TRUE(compareDiscoveryRequest( + EdsTypeUrl, "", {"failover_cluster_0"}, {"failover_cluster_0"}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", failover_xds_stream_.get())); + sendDiscoveryResponse( + EdsTypeUrl, {buildClusterLoadAssignment("failover_cluster_0")}, + {buildClusterLoadAssignment("failover_cluster_0")}, {}, "failover1", {}, + failover_xds_stream_.get()); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); + test_server_->waitForGaugeEq("cluster.failover_cluster_0.warming_state", 0); + EXPECT_TRUE(compareDiscoveryRequest(CdsTypeUrl, "failover1", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Listener, "", {}, {}, {}, false, + Grpc::Status::WellKnownGrpcStatus::Ok, "", + failover_xds_stream_.get())); + + // Envoy has received CDS and EDS responses, it means the failover is available. + // Now disconnect the failover source. + failover_xds_stream_->finishGrpcStream(Grpc::Status::Internal); + EXPECT_TRUE(failover_xds_connection_->close()); + ASSERT_TRUE(failover_xds_connection_->waitForDisconnect()); + + // Ensure Envoy alternates between primary and failover. + // Up to this step there were 3 CDS update failures. In each iteration of the + // next loop there are going to be 2 failures (one for primary and another for + // failover). + for (int i = 1; i < 3; ++i) { + // Wait longer due to the fixed 5 seconds failover . + waitForPrimaryXdsRetryTimer(2 * i + 1, 5); + + // The failover disconnected, so the next step is trying to connect to the + // primary source. Disconnect the primary source immediately. + primaryConnectionFailure(); + ASSERT_TRUE(xds_connection_->waitForDisconnect()); + + // Expect a connection to the failover source to be attempted. Disconnect + // immediately. + result = failover_xds_upstream_->waitForHttpConnection(*dispatcher_, failover_xds_connection_); + RELEASE_ASSERT(result, result.message()); + result = failover_xds_connection_->close(); + RELEASE_ASSERT(result, result.message()); + ASSERT_TRUE(failover_xds_connection_->waitForDisconnect()); + } } } // namespace Envoy diff --git a/test/extensions/dynamic_modules/BUILD b/test/extensions/dynamic_modules/BUILD new file mode 100644 index 000000000000..8c831226c66a --- /dev/null +++ b/test/extensions/dynamic_modules/BUILD @@ -0,0 +1,22 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "dynamic_modules_test", + srcs = ["dynamic_modules_test.cc"], + data = [ + "//test/extensions/dynamic_modules/test_data:no_op", + ], + deps = [ + "//source/extensions/dynamic_modules:dynamic_modules_lib", + "//test/test_common:environment_lib", + "//test/test_common:utility_lib", + ], +) diff --git a/test/extensions/dynamic_modules/dynamic_modules_test.cc b/test/extensions/dynamic_modules/dynamic_modules_test.cc new file mode 100644 index 000000000000..6f5f21f5988f --- /dev/null +++ b/test/extensions/dynamic_modules/dynamic_modules_test.cc @@ -0,0 +1,68 @@ +#include + +#include "envoy/common/exception.h" + +#include "source/extensions/dynamic_modules/dynamic_modules.h" + +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace DynamicModules { + +// This loads a shared object file from the test_data directory. +std::string testSharedObjectPath(std::string name) { + return TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/dynamic_modules/test_data/") + + "lib" + name + ".so"; +} + +TEST(DynamicModuleTest, InvalidPath) { + absl::StatusOr result = newDynamicModule("invalid_name", false); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument); +} + +TEST(DynamicModuleTest, LoadNoOp) { + using GetSomeVariableFuncType = int (*)(); + absl::StatusOr module = + newDynamicModule(testSharedObjectPath("no_op"), false); + EXPECT_TRUE(module.ok()); + const auto getSomeVariable = + module->get()->getFunctionPointer("getSomeVariable"); + EXPECT_EQ(getSomeVariable(), 1); + EXPECT_EQ(getSomeVariable(), 2); + EXPECT_EQ(getSomeVariable(), 3); + + // Release the module, and reload it. + module->reset(); + module = + newDynamicModule(testSharedObjectPath("no_op"), true); // This time, do not close the module. + EXPECT_TRUE(module.ok()); + + // This module must be reloaded and the variable must be reset. + const auto getSomeVariable2 = + (module->get()->getFunctionPointer("getSomeVariable")); + EXPECT_NE(getSomeVariable2, nullptr); + EXPECT_EQ(getSomeVariable2(), 1); // Start from 1 again. + EXPECT_EQ(getSomeVariable2(), 2); + EXPECT_EQ(getSomeVariable2(), 3); + + // Release the module, and reload it. + module->reset(); + module = newDynamicModule(testSharedObjectPath("no_op"), false); + EXPECT_TRUE(module.ok()); + + // This module must be the already loaded one, and the variable must be kept. + const auto getSomeVariable3 = + module->get()->getFunctionPointer("getSomeVariable"); + EXPECT_NE(getSomeVariable3, nullptr); + EXPECT_EQ(getSomeVariable3(), 4); // Start from 4. +} + +} // namespace DynamicModules +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/dynamic_modules/test_data/BUILD b/test/extensions/dynamic_modules/test_data/BUILD new file mode 100644 index 000000000000..f199f10d3218 --- /dev/null +++ b/test/extensions/dynamic_modules/test_data/BUILD @@ -0,0 +1,7 @@ +load("//test/extensions/dynamic_modules/test_data:test_data.bzl", "test_program") + +licenses(["notice"]) # Apache 2 + +package(default_visibility = ["//visibility:public"]) + +test_program(name = "no_op") diff --git a/test/extensions/dynamic_modules/test_data/no_op.c b/test/extensions/dynamic_modules/test_data/no_op.c new file mode 100644 index 000000000000..81815e007da7 --- /dev/null +++ b/test/extensions/dynamic_modules/test_data/no_op.c @@ -0,0 +1,5 @@ +int getSomeVariable() { + static int some_variable = 0; + some_variable++; + return some_variable; +} diff --git a/test/extensions/dynamic_modules/test_data/test_data.bzl b/test/extensions/dynamic_modules/test_data/test_data.bzl new file mode 100644 index 000000000000..fbe1af7f580e --- /dev/null +++ b/test/extensions/dynamic_modules/test_data/test_data.bzl @@ -0,0 +1,14 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +# This declares a cc_library target that is used to build a shared library. +# name + ".c" is the source file that is compiled to create the shared library. +def test_program(name): + cc_library( + name = name, + srcs = [name + ".c"], + linkopts = [ + "-shared", + "-fPIC", + ], + linkstatic = False, + ) diff --git a/test/extensions/filters/common/ext_authz/BUILD b/test/extensions/filters/common/ext_authz/BUILD index 02e8da4a7e29..a9c84c57d34a 100644 --- a/test/extensions/filters/common/ext_authz/BUILD +++ b/test/extensions/filters/common/ext_authz/BUILD @@ -36,7 +36,6 @@ envoy_cc_test( "//source/extensions/filters/common/ext_authz:ext_authz_grpc_lib", "//test/extensions/filters/common/ext_authz:ext_authz_test_common", "//test/mocks/tracing:tracing_mocks", - "//test/test_common:test_runtime_lib", "@envoy_api//envoy/service/auth/v3:pkg_cc_proto", "@envoy_api//envoy/type/v3:pkg_cc_proto", ], diff --git a/test/extensions/filters/common/ext_authz/ext_authz_grpc_impl_test.cc b/test/extensions/filters/common/ext_authz/ext_authz_grpc_impl_test.cc index cec883ca7506..a7832ddeda2a 100644 --- a/test/extensions/filters/common/ext_authz/ext_authz_grpc_impl_test.cc +++ b/test/extensions/filters/common/ext_authz/ext_authz_grpc_impl_test.cc @@ -11,7 +11,6 @@ #include "test/mocks/grpc/mocks.h" #include "test/mocks/stream_info/mocks.h" #include "test/mocks/tracing/mocks.h" -#include "test/test_common/test_runtime.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -180,6 +179,30 @@ TEST_F(ExtAuthzGrpcClientTest, AuthorizationDenied) { client_->onSuccess(std::move(check_response), span_); } +// Test the client when a gRPC status code unknown is received from the authorization server. +TEST_F(ExtAuthzGrpcClientTest, AuthorizationDeniedGrpcUnknownStatus) { + initialize(); + + auto check_response = std::make_unique(); + auto status = check_response->mutable_status(); + status->set_code(Grpc::Status::WellKnownGrpcStatus::Unknown); + auto authz_response = Response{}; + authz_response.status = CheckStatus::Denied; + + envoy::service::auth::v3::CheckRequest request; + expectCallSend(request); + client_->check(request_callbacks_, request, Tracing::NullSpan::instance(), stream_info_); + + Http::TestRequestHeaderMapImpl headers; + client_->onCreateInitialMetadata(headers); + EXPECT_EQ(nullptr, headers.RequestId()); + EXPECT_CALL(span_, setTag(Eq("ext_authz_status"), Eq("ext_authz_unauthorized"))); + EXPECT_CALL(request_callbacks_, onComplete_(WhenDynamicCastTo( + AuthzResponseNoAttributes(authz_response)))); + + client_->onSuccess(std::move(check_response), span_); +} + // Test the client when a denied response with additional HTTP attributes is received. TEST_F(ExtAuthzGrpcClientTest, AuthorizationDeniedWithAllAttributes) { initialize(); @@ -414,72 +437,6 @@ TEST_F(ExtAuthzGrpcClientTest, AuthorizationOkWithAppendActions) { span_); } -// Test the client when an error code response is received. -TEST_F(ExtAuthzGrpcClientTest, AuthorizationReturnsErrorOnBadGrpcCode) { - initialize(); - - auto check_response = std::make_unique(); - auto status = check_response->mutable_status(); - - ProtobufWkt::Struct expected_dynamic_metadata; - auto* metadata_fields = expected_dynamic_metadata.mutable_fields(); - (*metadata_fields)["foo"] = ValueUtil::stringValue("ok"); - (*metadata_fields)["bar"] = ValueUtil::numberValue(1); - - // The expected dynamic metadata is set to the outer check response, hence regardless the - // check_response's http_response value (either OkHttpResponse or DeniedHttpResponse) the dynamic - // metadata is set to be equal to the check response's dynamic metadata. - check_response->mutable_dynamic_metadata()->MergeFrom(expected_dynamic_metadata); - - status->set_code(Grpc::Status::WellKnownGrpcStatus::Unavailable); - - // This is the expected authz response. - auto authz_response = Response{}; - authz_response.status = CheckStatus::Error; - - authz_response.dynamic_metadata = expected_dynamic_metadata; - - envoy::service::auth::v3::CheckRequest request; - expectCallSend(request); - client_->check(request_callbacks_, request, Tracing::NullSpan::instance(), stream_info_); - - Http::TestRequestHeaderMapImpl headers; - client_->onCreateInitialMetadata(headers); - - EXPECT_CALL(request_callbacks_, onComplete_(WhenDynamicCastTo( - AuthzResponseNoAttributes(authz_response)))); - client_->onSuccess(std::move(check_response), span_); -} - -// Test the client when an error code response is received and -// process_ext_authz_grpc_error_codes_as_errors is false. -TEST_F(ExtAuthzGrpcClientTest, AuthorizationReturnsDeniedOnUnknownGrpcCodeWhenFeatureFlagDisabled) { - TestScopedRuntime scoped_runtime; - scoped_runtime.mergeValues( - {{"envoy.reloadable_features.process_ext_authz_grpc_error_codes_as_errors", "false"}}); - - initialize(); - - auto check_response = std::make_unique(); - auto status = check_response->mutable_status(); - status->set_code(Grpc::Status::WellKnownGrpcStatus::Unknown); - auto authz_response = Response{}; - authz_response.status = CheckStatus::Denied; - - envoy::service::auth::v3::CheckRequest request; - expectCallSend(request); - client_->check(request_callbacks_, request, Tracing::NullSpan::instance(), stream_info_); - - Http::TestRequestHeaderMapImpl headers; - client_->onCreateInitialMetadata(headers); - EXPECT_EQ(nullptr, headers.RequestId()); - EXPECT_CALL(span_, setTag(Eq("ext_authz_status"), Eq("ext_authz_unauthorized"))); - EXPECT_CALL(request_callbacks_, onComplete_(WhenDynamicCastTo( - AuthzResponseNoAttributes(authz_response)))); - - client_->onSuccess(std::move(check_response), span_); -} - } // namespace ExtAuthz } // namespace Common } // namespace Filters diff --git a/test/extensions/filters/http/cache/cache_filter_test.cc b/test/extensions/filters/http/cache/cache_filter_test.cc index d481e905799e..a0b0cd38457b 100644 --- a/test/extensions/filters/http/cache/cache_filter_test.cc +++ b/test/extensions/filters/http/cache/cache_filter_test.cc @@ -494,6 +494,88 @@ MATCHER_P2(RangeMatcher, begin, end, "") { testing::ExplainMatchResult(end, arg.end(), result_listener); } +TEST_F(CacheFilterTest, OnDestroyBeforeOnHeadersAbortsAction) { + request_headers_.setHost("CacheHitWithBody"); + auto mock_http_cache = std::make_shared(); + auto mock_lookup_context = std::make_unique>(); + EXPECT_CALL(*mock_http_cache, makeLookupContext(_, _)) + .WillOnce([&](LookupRequest&&, + Http::StreamDecoderFilterCallbacks&) -> std::unique_ptr { + return std::move(mock_lookup_context); + }); + EXPECT_CALL(*mock_lookup_context, getHeaders(_)).WillOnce([&](LookupHeadersCallback&& cb) { + std::unique_ptr response_headers = + std::make_unique(response_headers_); + cb(LookupResult{CacheEntryStatus::Ok, std::move(response_headers), 8, absl::nullopt}); + }); + auto filter = makeFilter(mock_http_cache, false); + EXPECT_EQ(filter->decodeHeaders(request_headers_, true), + Http::FilterHeadersStatus::StopAllIterationAndWatermark); + filter->onDestroy(); + // Nothing extra should happen when the posted lookup completion resolves, because + // the filter was destroyed. + dispatcher_->run(Event::Dispatcher::RunType::Block); +} + +TEST_F(CacheFilterTest, OnDestroyBeforeOnBodyAbortsAction) { + request_headers_.setHost("CacheHitWithBody"); + auto mock_http_cache = std::make_shared(); + auto mock_lookup_context = std::make_unique>(); + EXPECT_CALL(*mock_http_cache, makeLookupContext(_, _)) + .WillOnce([&](LookupRequest&&, + Http::StreamDecoderFilterCallbacks&) -> std::unique_ptr { + return std::move(mock_lookup_context); + }); + EXPECT_CALL(*mock_lookup_context, getHeaders(_)).WillOnce([&](LookupHeadersCallback&& cb) { + std::unique_ptr response_headers = + std::make_unique(response_headers_); + cb(LookupResult{CacheEntryStatus::Ok, std::move(response_headers), 5, absl::nullopt}); + }); + LookupBodyCallback body_callback; + EXPECT_CALL(*mock_lookup_context, getBody(RangeMatcher(0, 5), _)) + .WillOnce([&](const AdjustedByteRange&, LookupBodyCallback&& cb) { body_callback = cb; }); + auto filter = makeFilter(mock_http_cache, false); + EXPECT_EQ(filter->decodeHeaders(request_headers_, true), + Http::FilterHeadersStatus::StopAllIterationAndWatermark); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + filter->onDestroy(); + // onBody should do nothing because the filter was destroyed. + body_callback(std::make_unique("abcde")); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); +} + +TEST_F(CacheFilterTest, OnDestroyBeforeOnTrailersAbortsAction) { + request_headers_.setHost("CacheHitWithTrailers"); + auto mock_http_cache = std::make_shared(); + auto mock_lookup_context = std::make_unique>(); + EXPECT_CALL(*mock_http_cache, makeLookupContext(_, _)) + .WillOnce([&](LookupRequest&&, + Http::StreamDecoderFilterCallbacks&) -> std::unique_ptr { + return std::move(mock_lookup_context); + }); + EXPECT_CALL(*mock_lookup_context, getHeaders(_)).WillOnce([&](LookupHeadersCallback&& cb) { + std::unique_ptr response_headers = + std::make_unique(response_headers_); + cb(LookupResult{CacheEntryStatus::Ok, std::move(response_headers), 5, absl::nullopt, true}); + }); + EXPECT_CALL(*mock_lookup_context, getBody(RangeMatcher(0, 5), _)) + .WillOnce([&](const AdjustedByteRange&, LookupBodyCallback&& cb) { + cb(std::make_unique("abcde")); + }); + LookupTrailersCallback trailers_callback; + EXPECT_CALL(*mock_lookup_context, getTrailers(_)).WillOnce([&](LookupTrailersCallback&& cb) { + trailers_callback = cb; + }); + auto filter = makeFilter(mock_http_cache, false); + EXPECT_EQ(filter->decodeHeaders(request_headers_, true), + Http::FilterHeadersStatus::StopAllIterationAndWatermark); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + filter->onDestroy(); + // onTrailers should do nothing because the filter was destroyed. + trailers_callback(std::make_unique()); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); +} + TEST_F(CacheFilterTest, BodyReadFromCacheLimitedToBufferSizeChunks) { request_headers_.setHost("CacheHitWithBody"); // Set the buffer limit to 5 bytes, and we will have the file be of size @@ -799,6 +881,90 @@ TEST_F(CacheFilterTest, SuccessfulValidation) { } } +TEST_F(CacheFilterTest, SuccessfulValidationWithFilterDestroyedDuringContinueEncoding) { + request_headers_.setHost("SuccessfulValidation"); + const std::string body = "abc"; + const std::string etag = "abc123"; + const std::string last_modified_date = formatter_.now(time_source_); + { + // Create filter for request 1 + CacheFilterSharedPtr filter = makeFilter(simple_cache_); + + testDecodeRequestMiss(filter); + + // Encode response + // Add Etag & Last-Modified headers to the response for validation + response_headers_.setReferenceKey(Http::CustomHeaders::get().Etag, etag); + response_headers_.setReferenceKey(Http::CustomHeaders::get().LastModified, last_modified_date); + + Buffer::OwnedImpl buffer(body); + response_headers_.setContentLength(body.size()); + EXPECT_EQ(filter->encodeHeaders(response_headers_, false), Http::FilterHeadersStatus::Continue); + EXPECT_EQ(filter->encodeData(buffer, true), Http::FilterDataStatus::Continue); + // The cache getBody callback should be posted to the dispatcher. + // Run events on the dispatcher so that the callback is invoked. + dispatcher_->run(Event::Dispatcher::RunType::Block); + + filter->onStreamComplete(); + EXPECT_THAT(lookupStatus(), IsOkAndHolds(LookupStatus::CacheMiss)); + } + waitBeforeSecondRequest(); + { + // Create filter for request 2 + CacheFilterSharedPtr filter = makeFilter(simple_cache_, /*auto_destroy=*/false); + + // Make request require validation + request_headers_.setReferenceKey(Http::CustomHeaders::get().CacheControl, "no-cache"); + + // Decoding the request should find a cached response that requires validation. + // As far as decoding the request is concerned, this is the same as a cache miss with the + // exception of injecting validation precondition headers. + testDecodeRequestMiss(filter); + + // Make sure validation conditional headers are added + const Http::TestRequestHeaderMapImpl injected_headers = { + {"if-none-match", etag}, {"if-modified-since", last_modified_date}}; + EXPECT_THAT(request_headers_, IsSupersetOfHeaders(injected_headers)); + + // Encode 304 response + // Advance time to make sure the cached date is updated with the 304 date + const std::string not_modified_date = formatter_.now(time_source_); + Http::TestResponseHeaderMapImpl not_modified_response_headers = {{":status", "304"}, + {"date", not_modified_date}}; + + // The filter should stop encoding iteration when encodeHeaders is called as a cached response + // is being fetched and added to the encoding stream. StopIteration does not stop encodeData of + // the same filter from being called + EXPECT_EQ(filter->encodeHeaders(not_modified_response_headers, true), + Http::FilterHeadersStatus::StopIteration); + + // Check for the cached response headers with updated date + Http::TestResponseHeaderMapImpl updated_response_headers = response_headers_; + updated_response_headers.setDate(not_modified_date); + EXPECT_THAT(not_modified_response_headers, IsSupersetOfHeaders(updated_response_headers)); + + // A 304 response should not have a body, so encodeData should not be called + // However, if a body is present by mistake, encodeData should stop iteration until + // encoding the cached response is done + Buffer::OwnedImpl not_modified_body; + EXPECT_EQ(filter->encodeData(not_modified_body, true), + Http::FilterDataStatus::StopIterationAndBuffer); + + // The filter should add the cached response body to encoded data. + Buffer::OwnedImpl buffer(body); + EXPECT_CALL( + encoder_callbacks_, + addEncodedData(testing::Property(&Buffer::Instance::toString, testing::Eq(body)), true)); + EXPECT_CALL(encoder_callbacks_, continueEncoding()).WillOnce([&]() { filter->onDestroy(); }); + + // The cache getBody callback should be posted to the dispatcher. + // Run events on the dispatcher so that the callback is invoked. + dispatcher_->run(Event::Dispatcher::RunType::Block); + + ::testing::Mock::VerifyAndClearExpectations(&encoder_callbacks_); + } +} + TEST_F(CacheFilterTest, UnsuccessfulValidation) { request_headers_.setHost("UnsuccessfulValidation"); const std::string body = "abc"; diff --git a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc index 4cfa502e3e26..5bb5ea66e488 100644 --- a/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc +++ b/test/extensions/filters/http/dynamic_forward_proxy/proxy_filter_integration_test.cc @@ -291,12 +291,16 @@ name: envoy.clusters.dynamic_forward_proxy auto response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); ASSERT_TRUE(response->waitForEndStream()); EXPECT_EQ("503", response->headers().getStatusValue()); - EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("dns_resolution_failure")); + std::string access_log = waitForAccessLog(access_log_name_); + EXPECT_THAT(access_log, HasSubstr("dns_resolution_failure")); + EXPECT_FALSE(StringUtil::hasEmptySpace(access_log)); response = codec_client_->makeHeaderOnlyRequest(default_request_headers_); ASSERT_TRUE(response->waitForEndStream()); EXPECT_EQ("503", response->headers().getStatusValue()); - EXPECT_THAT(waitForAccessLog(access_log_name_, 1), HasSubstr("dns_resolution_failure")); + access_log = waitForAccessLog(access_log_name_, 1); + EXPECT_THAT(access_log, HasSubstr("dns_resolution_failure")); + EXPECT_FALSE(StringUtil::hasEmptySpace(access_log)); } void multipleRequestsMaybeReresolve(bool reresolve) { @@ -528,12 +532,16 @@ TEST_P(ProxyFilterIntegrationTest, RequestWithUnknownDomainAndNoCaching) { auto response = codec_client_->makeHeaderOnlyRequest(request_headers); ASSERT_TRUE(response->waitForEndStream()); EXPECT_EQ("503", response->headers().getStatusValue()); - EXPECT_THAT(waitForAccessLog(access_log_name_), HasSubstr("dns_resolution_failure")); + std::string access_log = waitForAccessLog(access_log_name_); + EXPECT_THAT(access_log, HasSubstr("dns_resolution_failure")); + EXPECT_FALSE(StringUtil::hasEmptySpace(access_log)); response = codec_client_->makeHeaderOnlyRequest(request_headers); ASSERT_TRUE(response->waitForEndStream()); EXPECT_EQ("503", response->headers().getStatusValue()); - EXPECT_THAT(waitForAccessLog(access_log_name_, 1), HasSubstr("dns_resolution_failure")); + access_log = waitForAccessLog(access_log_name_, 1); + EXPECT_THAT(access_log, HasSubstr("dns_resolution_failure")); + EXPECT_FALSE(StringUtil::hasEmptySpace(access_log)); } // Verify that after we populate the cache and reload the cluster we reattach to the cache with diff --git a/test/extensions/filters/http/ext_authz/config_test.cc b/test/extensions/filters/http/ext_authz/config_test.cc index 866081c2f491..bfb2a593b411 100644 --- a/test/extensions/filters/http/ext_authz/config_test.cc +++ b/test/extensions/filters/http/ext_authz/config_test.cc @@ -163,6 +163,60 @@ TEST_F(ExtAuthzFilterHttpTest, ExtAuthzFilterFactoryTestHttp) { testFilterFactory(ext_authz_config_yaml); } +TEST_F(ExtAuthzFilterHttpTest, FilterWithServerContext) { + const std::string ext_authz_config_yaml = R"EOF( + stat_prefix: "wall" + allowed_headers: + patterns: + - exact: baz + - prefix: x- + http_service: + server_uri: + uri: "ext_authz:9000" + cluster: "ext_authz" + timeout: 0.25s + authorization_request: + headers_to_add: + - key: foo + value: bar + - key: bar + value: foo + + authorization_response: + allowed_upstream_headers: + patterns: + - exact: baz + - prefix: x-success + allowed_client_headers: + patterns: + - exact: baz + - prefix: x-fail + allowed_upstream_headers_to_append: + patterns: + - exact: baz-append + - prefix: x-append + + path_prefix: /extauth + + failure_mode_allow: true + with_request_body: + max_request_bytes: 100 + pack_as_bytes: true + )EOF"; + + ExtAuthzFilterConfig factory; + ProtobufTypes::MessagePtr proto_config = factory.createEmptyConfigProto(); + TestUtility::loadFromYaml(ext_authz_config_yaml, *proto_config); + + testing::NiceMock context; + EXPECT_CALL(context, messageValidationVisitor()); + Http::FilterFactoryCb cb = + factory.createFilterFactoryFromProtoWithServerContext(*proto_config, "stats", context); + Http::MockFilterChainFactoryCallbacks filter_callback; + EXPECT_CALL(filter_callback, addStreamFilter(_)); + cb(filter_callback); +} + class ExtAuthzFilterGrpcTest : public ExtAuthzFilterTest { public: void testFilterFactoryAndFilterWithGrpcClient(const std::string& ext_authz_config_yaml) { diff --git a/test/extensions/filters/http/ext_proc/ext_proc_integration_test.cc b/test/extensions/filters/http/ext_proc/ext_proc_integration_test.cc index d1ee77911444..93c9300e18f3 100644 --- a/test/extensions/filters/http/ext_proc/ext_proc_integration_test.cc +++ b/test/extensions/filters/http/ext_proc/ext_proc_integration_test.cc @@ -182,6 +182,9 @@ class ExtProcIntegrationTest : public HttpIntegrationTest, test::integration::filters::LoggingTestFilterConfig logging_filter_config; logging_filter_config.set_logging_id(ext_proc_filter_name); logging_filter_config.set_upstream_cluster_name(valid_grpc_cluster_name); + // No need to check the bytes received for observability mode because it is a + // "send and go" mode. + logging_filter_config.set_check_received_bytes(!proto_config_.observability_mode()); envoy::extensions::filters::network::http_connection_manager::v3::HttpFilter logging_filter; logging_filter.set_name("logging-test-filter"); logging_filter.mutable_typed_config()->PackFrom(logging_filter_config); diff --git a/test/extensions/filters/http/ext_proc/filter_test.cc b/test/extensions/filters/http/ext_proc/filter_test.cc index 15c3023c90c7..6fd45bff4495 100644 --- a/test/extensions/filters/http/ext_proc/filter_test.cc +++ b/test/extensions/filters/http/ext_proc/filter_test.cc @@ -4261,7 +4261,7 @@ TEST_F(HttpFilter2Test, LastDecodeDataCallExceedsStreamBufferLimitWouldJustRaise envoy_grpc: cluster_name: "ext_proc_server" )EOF"); - HttpConnectionManagerImplMixin::setup(false, "fake-server"); + HttpConnectionManagerImplMixin::setup(Envoy::Http::SetupOpts().setServerName("fake-server")); HttpConnectionManagerImplMixin::initial_buffer_limit_ = 10; HttpConnectionManagerImplMixin::setUpBufferLimits(); @@ -4352,7 +4352,7 @@ TEST_F(HttpFilter2Test, LastEncodeDataCallExceedsStreamBufferLimitWouldJustRaise response_trailer_mode: "SKIP" )EOF"); - HttpConnectionManagerImplMixin::setup(false, "fake-server"); + HttpConnectionManagerImplMixin::setup(Envoy::Http::SetupOpts().setServerName("fake-server")); HttpConnectionManagerImplMixin::initial_buffer_limit_ = 10; HttpConnectionManagerImplMixin::setUpBufferLimits(); diff --git a/test/extensions/filters/http/ext_proc/http_client/BUILD b/test/extensions/filters/http/ext_proc/http_client/BUILD new file mode 100644 index 000000000000..d5c2826982dd --- /dev/null +++ b/test/extensions/filters/http/ext_proc/http_client/BUILD @@ -0,0 +1,26 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "http_client_test", + size = "small", + srcs = ["http_client_test.cc"], + extension_names = ["envoy.filters.http.ext_proc"], + tags = ["skip_on_windows"], + deps = [ + "//source/common/http:message_lib", + "//source/extensions/filters/http/ext_proc/http_client:http_client_lib", + "//test/mocks/server:factory_context_mocks", + "@envoy_api//envoy/extensions/filters/http/ext_proc/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/filters/http/ext_proc/http_client/http_client_test.cc b/test/extensions/filters/http/ext_proc/http_client/http_client_test.cc new file mode 100644 index 000000000000..27a6d83c9ef1 --- /dev/null +++ b/test/extensions/filters/http/ext_proc/http_client/http_client_test.cc @@ -0,0 +1,65 @@ +#include "envoy/extensions/filters/http/ext_proc/v3/ext_proc.pb.h" + +#include "source/common/http/message_impl.h" +#include "source/extensions/filters/http/ext_proc/http_client/http_client_impl.h" + +#include "test/mocks/server/server_factory_context.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ExternalProcessing { +namespace { + +class ExtProcHttpClientTest : public testing::Test { +public: + ~ExtProcHttpClientTest() override = default; + + void SetUp() override { client_ = std::make_unique(config_, context_); } + +protected: + envoy::extensions::filters::http::ext_proc::v3::ExternalProcessor config_; + testing::NiceMock context_; + Upstream::MockClusterManager& cm_{context_.cluster_manager_}; + std::unique_ptr client_; + testing::NiceMock async_request_{ + &cm_.thread_local_cluster_.async_client_}; +}; + +TEST_F(ExtProcHttpClientTest, Basic) { + SetUp(); + client_->sendRequest(); + client_->cancel(); + client_->context(); + Tracing::MockSpan parent_span; + client_->onBeforeFinalizeUpstreamSpan(parent_span, nullptr); + Http::AsyncClient::FailureReason reason = Envoy::Http::AsyncClient::FailureReason::Reset; + client_->onFailure(async_request_, reason); + + Http::ResponseHeaderMapPtr resp_headers_ok(new Http::TestResponseHeaderMapImpl({ + {":status", "200"}, + })); + Http::ResponseMessagePtr response_ok(new Http::ResponseMessageImpl(std::move(resp_headers_ok))); + client_->onSuccess(async_request_, std::move(response_ok)); + + Http::ResponseHeaderMapPtr resp_headers(new Http::TestResponseHeaderMapImpl({ + {":status", "403"}, + })); + Http::ResponseMessagePtr response(new Http::ResponseMessageImpl(std::move(resp_headers))); + client_->onSuccess(async_request_, std::move(response)); + + Http::ResponseHeaderMapPtr resp_headers_foo(new Http::TestResponseHeaderMapImpl({ + {":status", "foo"}, + })); + Http::ResponseMessagePtr response_foo(new Http::ResponseMessageImpl(std::move(resp_headers_foo))); + client_->onSuccess(async_request_, std::move(response_foo)); +} + +} // namespace +} // namespace ExternalProcessing +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/ext_proc/logging_test_filter.cc b/test/extensions/filters/http/ext_proc/logging_test_filter.cc index 30838fd74600..702bd61804d0 100644 --- a/test/extensions/filters/http/ext_proc/logging_test_filter.cc +++ b/test/extensions/filters/http/ext_proc/logging_test_filter.cc @@ -22,8 +22,10 @@ namespace ExternalProcessing { // A test filter that retrieve the logging info on encodeComplete. class LoggingTestFilter : public Http::PassThroughFilter { public: - LoggingTestFilter(const std::string& logging_id, const std::string& cluster_name) - : logging_id_(logging_id), expected_cluster_name_(cluster_name) {} + LoggingTestFilter(const std::string& logging_id, const std::string& cluster_name, + bool check_received_bytes) + : logging_id_(logging_id), expected_cluster_name_(cluster_name), + check_received_bytes_(check_received_bytes) {} void encodeComplete() override { ASSERT(decoder_callbacks_ != nullptr); const Envoy::StreamInfo::FilterStateSharedPtr& filter_state = @@ -32,7 +34,9 @@ class LoggingTestFilter : public Http::PassThroughFilter { filter_state->getDataReadOnly(logging_id_); if (ext_proc_logging_info != nullptr) { EXPECT_NE(ext_proc_logging_info->bytesSent(), 0); - EXPECT_NE(ext_proc_logging_info->bytesReceived(), 0); + if (check_received_bytes_) { + EXPECT_NE(ext_proc_logging_info->bytesReceived(), 0); + } ASSERT_TRUE(ext_proc_logging_info->upstreamHost() != nullptr); EXPECT_EQ(ext_proc_logging_info->upstreamHost()->cluster().name(), expected_cluster_name_); } @@ -41,6 +45,7 @@ class LoggingTestFilter : public Http::PassThroughFilter { private: std::string logging_id_; std::string expected_cluster_name_; + const bool check_received_bytes_; }; class LoggingTestFilterFactory : public Extensions::HttpFilters::Common::FactoryBase< @@ -53,7 +58,8 @@ class LoggingTestFilterFactory : public Extensions::HttpFilters::Common::Factory Server::Configuration::FactoryContext&) override { return [=](Http::FilterChainFactoryCallbacks& callbacks) -> void { callbacks.addStreamFilter(std::make_shared( - proto_config.logging_id(), proto_config.upstream_cluster_name())); + proto_config.logging_id(), proto_config.upstream_cluster_name(), + proto_config.check_received_bytes())); }; } }; diff --git a/test/extensions/filters/http/ext_proc/logging_test_filter.proto b/test/extensions/filters/http/ext_proc/logging_test_filter.proto index c6e5768b6860..293154343a33 100644 --- a/test/extensions/filters/http/ext_proc/logging_test_filter.proto +++ b/test/extensions/filters/http/ext_proc/logging_test_filter.proto @@ -5,4 +5,5 @@ package test.integration.filters; message LoggingTestFilterConfig { string logging_id = 1; string upstream_cluster_name = 2; + bool check_received_bytes = 3; } diff --git a/test/extensions/filters/http/ext_proc/mock_server.h b/test/extensions/filters/http/ext_proc/mock_server.h index 6ee9d92b32aa..d0b0389b0fd4 100644 --- a/test/extensions/filters/http/ext_proc/mock_server.h +++ b/test/extensions/filters/http/ext_proc/mock_server.h @@ -26,6 +26,7 @@ class MockStream : public ExternalProcessorStream { MOCK_METHOD(void, send, (envoy::service::ext_proc::v3::ProcessingRequest&&, bool)); MOCK_METHOD(bool, close, ()); MOCK_METHOD(const StreamInfo::StreamInfo&, streamInfo, (), (const override)); + MOCK_METHOD(StreamInfo::StreamInfo&, streamInfo, ()); MOCK_METHOD(void, notifyFilterDestroy, ()); }; diff --git a/test/extensions/filters/http/ext_proc/tracer_test_filter.cc b/test/extensions/filters/http/ext_proc/tracer_test_filter.cc index a76b91e911f8..3c9e5e1047dd 100644 --- a/test/extensions/filters/http/ext_proc/tracer_test_filter.cc +++ b/test/extensions/filters/http/ext_proc/tracer_test_filter.cc @@ -33,7 +33,7 @@ class Span : public Tracing::Span { Span(const std::string& operation_name, ExpectedSpansSharedPtr& expected_spans) : operation_name_(operation_name), expected_spans_(expected_spans){}; - ~Span() { + ~Span() override { EXPECT_TRUE(finished_) << fmt::format("span not finished in operation: {}", operation_name_); for (auto& expect_span : *expected_spans_) { if (expect_span.operation_name != operation_name_) { @@ -56,40 +56,42 @@ class Span : public Tracing::Span { } } - void setTag(absl::string_view name, absl::string_view value) { - tags_.insert_or_assign(name.data(), value.data()); + void setTag(absl::string_view name, absl::string_view value) override { + tags_.insert_or_assign(std::string(name), std::string(value)); } - void setOperation(absl::string_view operation_name) { operation_name_ = operation_name; } - void setSampled(bool do_sample) { sampled_ = do_sample; } - void injectContext(Tracing::TraceContext& trace_context, const Tracing::UpstreamContext&) { + void setOperation(absl::string_view operation_name) override { operation_name_ = operation_name; } + void setSampled(bool do_sample) override { sampled_ = do_sample; } + + void injectContext(Tracing::TraceContext& trace_context, + const Tracing::UpstreamContext&) override { std::string traceparent_header_value = "1"; traceParentHeader().setRefKey(trace_context, traceparent_header_value); context_injected_ = true; } - void setBaggage(absl::string_view, absl::string_view) { /* not implemented */ + void setBaggage(absl::string_view, absl::string_view) override { /* not implemented */ } - void log(SystemTime, const std::string&) { /* not implemented */ + void log(SystemTime, const std::string&) override { /* not implemented */ } - std::string getBaggage(absl::string_view) { + std::string getBaggage(absl::string_view) override { /* not implemented */ return EMPTY_STRING; }; - std::string getTraceId() const { + std::string getTraceId() const override { /* not implemented */ return EMPTY_STRING; }; - std::string getSpanId() const { + std::string getSpanId() const override { /* not implemented */ return EMPTY_STRING; }; Tracing::SpanPtr spawnChild(const Tracing::Config&, const std::string& operation_name, - SystemTime) { + SystemTime) override { return std::make_unique(operation_name, expected_spans_); } - void finishSpan() { finished_ = true; } + void finishSpan() override { finished_ = true; } private: std::string operation_name_; @@ -106,7 +108,7 @@ class Driver : public Tracing::Driver, Logger::Loggable { Driver(const test::integration::filters::TracerTestConfig& test_config, Server::Configuration::CommonFactoryContext&) : expected_spans_(std::make_shared>()) { - for (auto expected_span : test_config.expect_spans()) { + for (const auto& expected_span : test_config.expect_spans()) { ExpectedSpan span; span.operation_name = expected_span.operation_name(); span.sampled = expected_span.sampled(); @@ -123,7 +125,7 @@ class Driver : public Tracing::Driver, Logger::Loggable { return std::make_unique(operation_name, expected_spans_); }; - ~Driver() { + ~Driver() override { for (auto& span : *expected_spans_) { EXPECT_TRUE(span.tested) << fmt::format("missing span with operation '{}'", span.operation_name); diff --git a/test/extensions/filters/http/ext_proc/unit_test_fuzz/mocks.h b/test/extensions/filters/http/ext_proc/unit_test_fuzz/mocks.h index f346ee34b8e9..49ff067dd353 100644 --- a/test/extensions/filters/http/ext_proc/unit_test_fuzz/mocks.h +++ b/test/extensions/filters/http/ext_proc/unit_test_fuzz/mocks.h @@ -21,6 +21,7 @@ class MockStream : public ExternalProcessing::ExternalProcessorStream { (envoy::service::ext_proc::v3::ProcessingRequest && request, bool end_stream)); MOCK_METHOD(bool, close, ()); MOCK_METHOD(const StreamInfo::StreamInfo&, streamInfo, (), (const override)); + MOCK_METHOD(StreamInfo::StreamInfo&, streamInfo, ()); MOCK_METHOD(void, notifyFilterDestroy, ()); }; diff --git a/test/extensions/filters/http/file_system_buffer/filter_test.cc b/test/extensions/filters/http/file_system_buffer/filter_test.cc index c781c8461953..846b912ebfef 100644 --- a/test/extensions/filters/http/file_system_buffer/filter_test.cc +++ b/test/extensions/filters/http/file_system_buffer/filter_test.cc @@ -270,7 +270,8 @@ TEST_F(FileSystemBufferFilterTest, DoesNotBufferRequestWhenContentLengthPresent) inject_content_length_if_necessary: {} )"); request_headers_.setContentLength(6); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(request_headers_, false)); Buffer::OwnedImpl data1("hello"); Buffer::OwnedImpl data2(" banana"); EXPECT_EQ(Http::FilterDataStatus::StopIterationNoBuffer, filter_->decodeData(data1, false)); @@ -290,7 +291,8 @@ TEST_F(FileSystemBufferFilterTest, DoesNotBufferResponseWhenContentLengthPresent inject_content_length_if_necessary: {} )"); response_headers_.setContentLength(6); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); Buffer::OwnedImpl data1("hello"); Buffer::OwnedImpl data2(" banana"); EXPECT_EQ(Http::FilterDataStatus::StopIterationNoBuffer, filter_->encodeData(data1, false)); @@ -312,7 +314,8 @@ constexpr int outerWatermarkAfterIntercepting() { TEST_F(FileSystemBufferFilterTest, BuffersResponseWhenDownstreamIsSlow) { createFilterFromYaml(minimal_config); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); Buffer::OwnedImpl data1("hello"); Buffer::OwnedImpl data2(" banana"); sendResponseHighWatermark(); @@ -340,7 +343,8 @@ TEST_F(FileSystemBufferFilterTest, response: memory_buffer_bytes_limit: 6 )"); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); Buffer::OwnedImpl data1("hello "); Buffer::OwnedImpl data2("wor"); Buffer::OwnedImpl data3("ld"); @@ -441,7 +445,8 @@ TEST_F(FileSystemBufferFilterTest, ResponseSlowsWhenTotalBufferSizeExceededAndSt memory_buffer_bytes_limit: 10 storage_buffer_bytes_limit: 0 )"); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); sendResponseHighWatermark(); Buffer::OwnedImpl data1("hello "); Buffer::OwnedImpl data2("wor"); @@ -475,7 +480,8 @@ TEST_F(FileSystemBufferFilterTest, ResponseSlowsWhenDiskWriteTakesTooLongAndWate memory_buffer_bytes_limit: 10 storage_buffer_queue_high_watermark_bytes: 10 )"); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); // Stream recipient says stop sending right away. sendResponseHighWatermark(); Buffer::OwnedImpl data1("hello worm"); diff --git a/test/extensions/filters/http/grpc_field_extraction/filter_config_test.cc b/test/extensions/filters/http/grpc_field_extraction/filter_config_test.cc index 55485685d229..e973387b1bd3 100644 --- a/test/extensions/filters/http/grpc_field_extraction/filter_config_test.cc +++ b/test/extensions/filters/http/grpc_field_extraction/filter_config_test.cc @@ -200,6 +200,11 @@ extractions_by_method: { value: { } } + request_field_extractions: { + key: "repeated_supported_types.map" + value: { + } + } } })pb"); *proto_config_.mutable_descriptor_set()->mutable_filename() = diff --git a/test/extensions/filters/http/grpc_field_extraction/filter_test.cc b/test/extensions/filters/http/grpc_field_extraction/filter_test.cc index 166b1b322dd5..b4cf646a959e 100644 --- a/test/extensions/filters/http/grpc_field_extraction/filter_test.cc +++ b/test/extensions/filters/http/grpc_field_extraction/filter_test.cc @@ -639,6 +639,11 @@ extractions_by_method: { value: { } } + request_field_extractions: { + key: "repeated_supported_types.map" + value: { + } + } } })pb"); TestRequestHeaderMapImpl req_headers = @@ -677,6 +682,8 @@ repeated_supported_types: { sfixed64: 1111 float: 1.212 double: 1.313 + map { key: "key1" value: "value1" } + map { key: "key2" value: "value2" } } )pb"); @@ -853,6 +860,25 @@ fields { } } } +} +fields { + key: "repeated_supported_types.map" + value { + list_value { + values { + struct_value { + fields { + key: "key1" + value { string_value: "value1" } + } + fields { + key: "key2" + value { string_value: "value2" } + } + } + } + } + } })pb"); })); EXPECT_EQ(Envoy::Http::FilterDataStatus::Continue, filter_->decodeData(*request_data, true)); diff --git a/test/extensions/filters/http/jwt_authn/matcher_test.cc b/test/extensions/filters/http/jwt_authn/matcher_test.cc index 885cba5a57bd..916b8e993a4c 100644 --- a/test/extensions/filters/http/jwt_authn/matcher_test.cc +++ b/test/extensions/filters/http/jwt_authn/matcher_test.cc @@ -253,6 +253,30 @@ TEST_F(MatcherTest, TestMatchPathSeparatedPrefixBaseCondition) { EXPECT_FALSE(matcher->matches(headers)); } +TEST_F(MatcherTest, TestMatchPathMatchPolicy) { + const char config[] = R"(match: + path_match_policy: + name: envoy.path.match.uri_template.uri_template_matcher + typed_config: + "@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig + path_template: "/bar/*/foo" + )"; + MatcherConstPtr matcher = createMatcher(config); + auto headers = TestRequestHeaderMapImpl{{":path", "/bar/test/foo"}}; + EXPECT_TRUE(matcher->matches(headers)); +} + +TEST_F(MatcherTest, TestMatchPathMatchPolicyError) { + const char config[] = R"(match: + path_match_policy: + name: envoy.path.match.uri_template.uri_template_matcher + typed_config: + "@type": type.googleapis.com/envoy.extensions.path.match.uri_template.v3.UriTemplateMatchConfig + wrong_key: "/bar/*/foo" + )"; + EXPECT_THROW_WITH_REGEX(createMatcher(config), EnvoyException, "INVALID_ARGUMENT") +} + } // namespace } // namespace JwtAuthn } // namespace HttpFilters diff --git a/test/extensions/filters/http/oauth2/config_test.cc b/test/extensions/filters/http/oauth2/config_test.cc index e16fb0ca9b9d..8810337f1a07 100644 --- a/test/extensions/filters/http/oauth2/config_test.cc +++ b/test/extensions/filters/http/oauth2/config_test.cc @@ -95,6 +95,7 @@ TEST(ConfigTest, CreateFilter) { oauth_expires: OauthExpires id_token: IdToken refresh_token: RefreshToken + cookie_domain: example.com authorization_endpoint: https://oauth.com/oauth/authorize/ redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/callback" redirect_path_matcher: @@ -222,6 +223,7 @@ TEST(ConfigTest, WrongCombinationOfPreserveAuthorizationAndForwardBearer) { oauth_expires: OauthExpires id_token: IdToken refresh_token: RefreshToken + cookie_domain: example.com authorization_endpoint: https://oauth.com/oauth/authorize/ redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/callback" redirect_path_matcher: diff --git a/test/extensions/filters/http/oauth2/filter_test.cc b/test/extensions/filters/http/oauth2/filter_test.cc index 41039b9322a7..a32ae62de283 100644 --- a/test/extensions/filters/http/oauth2/filter_test.cc +++ b/test/extensions/filters/http/oauth2/filter_test.cc @@ -115,7 +115,7 @@ class OAuth2Test : public testing::TestWithParam { ::envoy::extensions::filters::http::oauth2::v3::OAuth2Config_AuthType:: OAuth2Config_AuthType_URL_ENCODED_BODY, int default_refresh_token_expires_in = 0, bool preserve_authorization_header = false, - bool disable_id_token_set_cookie = false) { + bool disable_id_token_set_cookie = false, bool set_cookie_domain = false) { envoy::extensions::filters::http::oauth2::v3::OAuth2Config p; auto* endpoint = p.mutable_token_endpoint(); endpoint->set_cluster("auth.example.com"); @@ -156,6 +156,9 @@ class OAuth2Test : public testing::TestWithParam { credentials->mutable_hmac_secret()->set_name("hmac"); // Skipping setting credentials.cookie_names field should give default cookie names: // BearerToken, OauthHMAC, and OauthExpires. + if (set_cookie_domain) { + credentials->set_cookie_domain("example.com"); + } MessageUtil::validate(p, ProtobufMessage::getStrictValidationVisitor()); @@ -1312,6 +1315,106 @@ TEST_F(OAuth2Test, OAuthTestFullFlowPostWithParametersFillRefreshAndIdToken) { filter_->finishGetAccessTokenFlow(); } +/** + * Testing oauth state with cookie domain. + * + * Expected behavior: Cookie domain should be set to the domain in the config. + */ +TEST_F(OAuth2Test, OAuthTestFullFlowPostWithCookieDomain) { + { + TestScopedRuntime scoped_runtime; + scoped_runtime.mergeValues({ + {"envoy.reloadable_features.hmac_base64_encoding_only", "true"}, + }); + init(getConfig(true, false, + ::envoy::extensions::filters::http::oauth2::v3::OAuth2Config_AuthType:: + OAuth2Config_AuthType_URL_ENCODED_BODY, + 0, false, false, true /* set_cookie_domain */)); + // First construct the initial request to the oauth filter with URI parameters. + Http::TestRequestHeaderMapImpl first_request_headers{ + {Http::Headers::get().Path.get(), "/test?name=admin&level=trace"}, + {Http::Headers::get().Host.get(), "traffic.example.com"}, + {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Post}, + {Http::Headers::get().Scheme.get(), "https"}, + }; + + // This is the immediate response - a redirect to the auth cluster. + Http::TestResponseHeaderMapImpl first_response_headers{ + {Http::Headers::get().Status.get(), "302"}, + {Http::Headers::get().Location.get(), + "https://auth.example.com/oauth/" + "authorize/?client_id=" + + TEST_CLIENT_ID + + "&redirect_uri=https%3A%2F%2Ftraffic.example.com%2F_oauth" + "&response_type=code" + "&scope=" + + TEST_ENCODED_AUTH_SCOPES + + "&state=https%3A%2F%2Ftraffic.example.com%2Ftest%3Fname%3Dadmin%26level%3Dtrace" + "&resource=oauth2-resource&resource=http%3A%2F%2Fexample.com" + "&resource=https%3A%2F%2Fexample.com%2Fsome%2Fpath%252F..%252F%2Futf8%C3%83%3Bfoo%" + "3Dbar%" + "3Fvar1%3D1%26var2%3D2"}, + }; + + // Fail the validation to trigger the OAuth flow. + EXPECT_CALL(*validator_, setParams(_, _)); + EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false)); + + // Check that the redirect includes URL encoded query parameter characters. + EXPECT_CALL(decoder_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&first_response_headers), true)); + + // This represents the beginning of the OAuth filter. + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(first_request_headers, false)); + + // This represents the callback request from the authorization server. + Http::TestRequestHeaderMapImpl second_request_headers{ + {Http::Headers::get().Path.get(), + "/_oauth?code=123&state=https%3A%2F%2Ftraffic.example.com%" + "2Ftest%3Fname%3Dadmin%26level%3Dtrace"}, + {Http::Headers::get().Host.get(), "traffic.example.com"}, + {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, + {Http::Headers::get().Scheme.get(), "https"}, + }; + // Deliberately fail the HMAC validation check. + EXPECT_CALL(*validator_, setParams(_, _)); + EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false)); + + EXPECT_CALL(*oauth_client_, + asyncGetAccessToken("123", TEST_CLIENT_ID, "asdf_client_secret_fdsa", + "https://traffic.example.com" + TEST_CALLBACK, + AuthType::UrlEncodedBody)); + + // Invoke the callback logic. As a side effect, state_ will be populated. + EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndBuffer, + filter_->decodeHeaders(second_request_headers, false)); + + EXPECT_EQ(1, config_->stats().oauth_unauthorized_rq_.value()); + EXPECT_EQ(config_->clusterName(), "auth.example.com"); + + // Expected response after the callback & validation is complete - verifying we kept the + // state and method of the original request, including the query string parameters. + Http::TestRequestHeaderMapImpl second_response_headers{ + {Http::Headers::get().Status.get(), "302"}, + {Http::Headers::get().SetCookie.get(), + "OauthHMAC=fV62OgLipChTQQC3UFgDp+l5sCiSb3zt7nCoJiVivWw=;" + "domain=example.com;path=/;Max-Age=;secure;HttpOnly"}, + {Http::Headers::get().SetCookie.get(), + "OauthExpires=;domain=example.com;path=/;Max-Age=;secure;HttpOnly"}, + {Http::Headers::get().SetCookie.get(), + "BearerToken=;domain=example.com;path=/;Max-Age=;secure;HttpOnly"}, + {Http::Headers::get().Location.get(), + "https://traffic.example.com/test?name=admin&level=trace"}, + }; + + EXPECT_CALL(decoder_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&second_response_headers), true)); + + filter_->finishGetAccessTokenFlow(); + } +} + class DisabledIdTokenTests : public OAuth2Test { public: DisabledIdTokenTests() : OAuth2Test(false) { diff --git a/test/extensions/filters/http/proto_message_logging/logging_util/BUILD b/test/extensions/filters/http/proto_message_logging/logging_util/BUILD new file mode 100644 index 000000000000..d23ca6e27937 --- /dev/null +++ b/test/extensions/filters/http/proto_message_logging/logging_util/BUILD @@ -0,0 +1,34 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "logging_util_test", + srcs = ["logging_util_test.cc"], + data = [ + "//test/proto:logging.proto", + "//test/proto:logging_proto_descriptor", + ], + deps = [ + "//source/extensions/filters/http/proto_message_logging/logging_util", + "//test/proto:logging_proto_cc_proto", + "//test/test_common:environment_lib", + "//test/test_common:status_utility_lib", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_protobuf//:protobuf", + "@com_google_protoconverter//:all", + "@com_google_protofieldextraction//:all_libs", + "@com_google_protofieldextraction//proto_field_extraction/test_utils:utils", + "@com_google_protoprocessinglib//proto_processing_lib/proto_scrubber:cloud_audit_log_field_checker", + "@ocp//ocpdiag/core/testing:status_matchers", + ], +) diff --git a/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.cc b/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.cc new file mode 100644 index 000000000000..c315fb2f2a8e --- /dev/null +++ b/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.cc @@ -0,0 +1,961 @@ +#include +#include +#include +#include +#include + +#include "source/extensions/filters/http/proto_message_logging/logging_util/logging_util.h" + +#include "test/proto/logging.pb.h" +#include "test/test_common/environment.h" +#include "test/test_common/logging.h" +#include "test/test_common/status_utility.h" +#include "test/test_common/utility.h" + +#include "absl/log/check.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "ocpdiag/core/compat/status_macros.h" +#include "ocpdiag/core/testing/status_matchers.h" +#include "proto_field_extraction/message_data/cord_message_data.h" +#include "proto_field_extraction/test_utils/utils.h" +#include "proto_processing_lib/proto_scrubber/cloud_audit_log_field_checker.h" +#include "proto_processing_lib/proto_scrubber/proto_scrubber.h" +#include "proto_processing_lib/proto_scrubber/proto_scrubber_enums.h" +#include "proto_processing_lib/proto_scrubber/utility.h" +#include "src/google/protobuf/util/converter/type_info.h" + +namespace Envoy { +namespace Extensions { +namespace HttpFilters { +namespace ProtoMessageLogging { +namespace { + +using ::Envoy::Protobuf::Field; +using ::Envoy::Protobuf::FieldMask; +using ::Envoy::Protobuf::Type; +using ::Envoy::Protobuf::field_extraction::CordMessageData; +using ::Envoy::Protobuf::field_extraction::testing::TypeHelper; +using ::Envoy::Protobuf::io::CodedInputStream; +using ::Envoy::ProtobufWkt::Struct; +using ::Envoy::StatusHelpers::IsOkAndHolds; +using ::Envoy::StatusHelpers::StatusIs; +using ::logging::TestRequest; +using ::logging::TestResponse; +using ::proto_processing_lib::proto_scrubber::CloudAuditLogFieldChecker; +using ::proto_processing_lib::proto_scrubber::ProtoScrubber; +using ::proto_processing_lib::proto_scrubber::ScrubberContext; +using ::testing::ValuesIn; + +// The type property value that will be included into the converted Struct. +constexpr char kTypeProperty[] = "@type"; + +const char kTestRequest[] = R"pb( + id: 123445 + bucket { + name: "test-bucket" + ratio: 0.8 + objects: "test-object-1" + objects: "test-object-2" + objects: "test-object-3" + } + proto2_message { + repeated_strings: [ "repeated-string-0", "repeated-string-1" ] + repeated_enum: [ PROTO2_ALPHA, PROTO2_BETA, PROTO2_ALPHA, PROTO2_GAMMA ] + repeated_double: [ 0.42 ] + repeated_float: [ 0.42, 1.98 ] + repeated_int64: [ 12, -5, 20 ] + repeated_uint64: [ 12, 190, 20, 800 ] + repeated_int32: [ 1, -5, 4, 100, -780 ] + repeated_fixed64: [ 1, 2, 89, 3, 56, 49 ] + repeated_fixed32: [ 1, 2, 89, 3, 56, 49, 90 ] + repeated_bool: [ True, False, False, True, True ] + repeated_uint32: [ 1, 2, 89, 3, 56, 49, 90, 0 ] + repeated_sfixed64: [ 1, 2, -89, 3, 56, -49 ] + repeated_sfixed32: [ 1, 2, -89, 3, 56, -49, 90 ] + repeated_sint32: [ 12, -5, 0, -7, 180 ] + repeated_sint64: [ 12, -5, 0, -9, 90, 39028 ] + } + repeated_strings: [ "repeated-string-0" ] + repeated_enum: [ ALPHA, BETA, TEST_ENUM_UNSPECIFIED, GAMMA ] + repeated_double: [ 0.42 ] + repeated_float: [ 0.42, 1.98 ] + repeated_int64: [ 12, -5, 20 ] + repeated_uint64: [ 12, 190, 20, 800 ] + repeated_int32: [ 1, -5, 4, 100, -780 ] + repeated_fixed64: [ 1, 2, 89, 3, 56, 49 ] + repeated_fixed32: [ 1, 2, 89, 3, 56, 49, 90 ] + repeated_bool: [ True, False, False, True, True ] + repeated_uint32: [ 1, 2, 89, 3, 56, 49, 90, 0 ] + repeated_sfixed64: [ 1, 2, -89, 3, 56, -49 ] + repeated_sfixed32: [ 1, 2, -89, 3, 56, -49, 90 ] + repeated_sint32: [ 12, -5, 0, -7, 180 ] + repeated_sint64: [ 12, -5, 0, -9, 90, 39028 ] +)pb"; + +const char kTestResponse[] = R"pb( + buckets { + name: "test-bucket-0" + ratio: 0.8 + objects: "test-object-01" + objects: "test-object-02" + objects: "test-object-03" + } + buckets { + name: "test-bucket-1" + ratio: 0.9 + objects: "test-object-11" + objects: "test-object-12" + objects: "test-object-13" + } + sub_buckets { + key: "test-bucket-2" + value { name: "test-bucket-2" ratio: 0.5 objects: "test-object-21" } + } + sub_buckets { + key: "test-bucket-3" + value { name: "test-bucket-3" ratio: 0.2 objects: "test-object-31" } + } + bucket_present { name: "bucket_present" } + sub_message { bucket_present { name: "bucket_present" } } +)pb"; + +class AuditLoggingUtilTest : public ::testing::Test { +protected: + AuditLoggingUtilTest() = default; + const Protobuf::Type* FindType(const std::string& type_url) { + absl::StatusOr result = type_helper_->ResolveTypeUrl(type_url); + if (!result.ok()) { + return nullptr; + } + return result.value(); + } + + void SetUp() override { + const std::string descriptor_path = + TestEnvironment::runfilesPath("test/proto/logging.descriptor"); + absl::StatusOr> status = TypeHelper::Create(descriptor_path); + type_helper_ = std::move(status.value()); + + type_finder_ = std::bind_front(&AuditLoggingUtilTest::FindType, this); + + if (!Protobuf::TextFormat::ParseFromString(kTestRequest, &test_request_proto_)) { + LOG(ERROR) << "Failed to parse textproto: " << kTestRequest; + } + test_request_raw_proto_ = CordMessageData(test_request_proto_.SerializeAsCord()); + request_type_ = type_finder_("type.googleapis.com/" + "logging.TestRequest"); + + if (!Protobuf::TextFormat::ParseFromString(kTestResponse, &test_response_proto_)) { + LOG(ERROR) << "Failed to parse textproto: " << kTestResponse; + } + test_response_raw_proto_ = CordMessageData(test_response_proto_.SerializeAsCord()); + response_type_ = type_finder_("type.googleapis.com/" + "logging.TestResponse"); + + labels_.clear(); + } + + FieldMask* GetFieldMaskWith(const std::string& path) { + field_mask_.clear_paths(); + field_mask_.add_paths(path); + return &field_mask_; + } + + // Helper function to create a Struct with nested fields + Struct CreateNestedStruct(const std::vector& path, const std::string& final_value) { + Struct root; + Struct* current = &root; + for (const auto& piece : path) { + (*current->mutable_fields())[piece].mutable_struct_value(); + current = (*current->mutable_fields())[piece].mutable_struct_value(); + } + (*current->mutable_fields())[final_value].mutable_string_value(); + return root; + } + + // A TypeHelper for testing. + std::unique_ptr type_helper_ = nullptr; + + std::function type_finder_; + + TestRequest test_request_proto_; + Protobuf::field_extraction::CordMessageData test_request_raw_proto_; + const Type* request_type_; + + TestResponse test_response_proto_; + Protobuf::field_extraction::CordMessageData test_response_raw_proto_; + const Type* response_type_; + + FieldMask field_mask_; + + Envoy::Protobuf::Map labels_; +}; + +TEST_F(AuditLoggingUtilTest, IsEmptyStruct_EmptyStruct) { + ProtobufWkt::Struct message_struct; + message_struct.mutable_fields()->insert({kTypeProperty, ProtobufWkt::Value()}); + EXPECT_TRUE(IsEmptyStruct(message_struct)); +} + +TEST_F(AuditLoggingUtilTest, IsEmptyStruct_NonEmptyStruct) { + ProtobufWkt::Struct message_struct; + message_struct.mutable_fields()->insert({kTypeProperty, ProtobufWkt::Value()}); + message_struct.mutable_fields()->insert({"another_field", ProtobufWkt::Value()}); + EXPECT_FALSE(IsEmptyStruct(message_struct)); +} + +TEST_F(AuditLoggingUtilTest, IsLabelName_ValidLabel) { EXPECT_TRUE(IsLabelName("{label}")); } + +TEST_F(AuditLoggingUtilTest, IsLabelName_EmptyString) { EXPECT_FALSE(IsLabelName("")); } + +TEST_F(AuditLoggingUtilTest, GetLabelName_RemovesCurlyBraces) { + EXPECT_EQ(GetLabelName("{test}"), "test"); +} + +TEST_F(AuditLoggingUtilTest, GetLabelName_NoCurlyBraces) { + EXPECT_EQ(GetLabelName("test"), "test"); +} + +TEST_F(AuditLoggingUtilTest, GetLabelName_EmptyString) { EXPECT_EQ(GetLabelName(""), ""); } + +TEST_F(AuditLoggingUtilTest, GetMonitoredResourceLabels_BasicExtraction) { + GetMonitoredResourceLabels("project/*/bucket/{bucket}/object/{object}", + "project/myproject/bucket/mybucket/object/myobject", &labels_); + + EXPECT_EQ(labels_.size(), 2); + EXPECT_EQ(labels_["bucket"], "mybucket"); + EXPECT_EQ(labels_["object"], "myobject"); +} + +TEST_F(AuditLoggingUtilTest, StringToDirectiveMap_CorrectMapping) { + const auto& map = StringToDirectiveMap(); + + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(map.at(kAuditRedact), AuditDirective::AUDIT_REDACT); + EXPECT_EQ(map.at(kAudit), AuditDirective::AUDIT); +} + +TEST_F(AuditLoggingUtilTest, AuditDirectiveFromString_ValidDirective) { + auto directive = AuditDirectiveFromString(kAuditRedact); + ASSERT_TRUE(directive.has_value()); + EXPECT_EQ(directive.value(), AuditDirective::AUDIT_REDACT); + + directive = AuditDirectiveFromString(kAudit); + ASSERT_TRUE(directive.has_value()); + EXPECT_EQ(directive.value(), AuditDirective::AUDIT); +} + +TEST_F(AuditLoggingUtilTest, AuditDirectiveFromString_InvalidDirective) { + auto directive = AuditDirectiveFromString("invalid_directive"); + EXPECT_FALSE(directive.has_value()); +} + +TEST_F(AuditLoggingUtilTest, GetMonitoredResourceLabels_MissingLabelsInResource) { + GetMonitoredResourceLabels("project/*/bucket/{bucket}/object/{object}", + "project/myproject/bucket/mybucket", &labels_); + + EXPECT_EQ(labels_.size(), 1); + EXPECT_EQ(labels_["bucket"], "mybucket"); + EXPECT_EQ(labels_.find("object"), labels_.end()); +} + +TEST_F(AuditLoggingUtilTest, GetMonitoredResourceLabels_ExtraSegmentsInResource) { + GetMonitoredResourceLabels("project/*/bucket/{bucket}/object/{object}", + "project/myproject/bucket/mybucket/object/myobject/extra", &labels_); + + EXPECT_EQ(labels_.size(), 2); + EXPECT_EQ(labels_["bucket"], "mybucket"); + EXPECT_EQ(labels_["object"], "myobject"); +} + +TEST_F(AuditLoggingUtilTest, GetMonitoredResourceLabels_WithNoLabels) { + GetMonitoredResourceLabels("project/*/bucket/*/object/*", + "project/myproject/bucket/mybucket/object/myobject", &labels_); + + EXPECT_EQ(labels_.size(), 0); +} + +TEST_F(AuditLoggingUtilTest, GetMonitoredResourceLabels_EmptyLabelExtractor) { + GetMonitoredResourceLabels("", "project/myproject/bucket/mybucket/object/myobject", &labels_); + + EXPECT_EQ(labels_.size(), 0); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_EmptyPath) { + Struct message_struct = CreateNestedStruct({"level1", "level2"}, "value"); + EXPECT_TRUE(RedactStructRecursively({}, {}, &message_struct).ok()); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_InvalidPath) { + Struct message_struct = CreateNestedStruct({"level1", "level2"}, "value"); + std::vector path_pieces = {"invalid", "path_end"}; + EXPECT_TRUE( + RedactStructRecursively(path_pieces.cbegin(), path_pieces.cend(), &message_struct).ok()); + + // Verify that the field "level2" has been replaced with an empty Struct + const auto& level1_field = message_struct.fields().at("level1"); + EXPECT_TRUE(level1_field.has_struct_value()); + const auto& level2_field = level1_field.struct_value().fields().at("level2"); + EXPECT_TRUE(level2_field.has_struct_value()); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_ValidPath) { + Struct message_struct = CreateNestedStruct({"level1", "level2"}, "value"); + std::vector path_pieces = {"level1", "level2"}; + EXPECT_TRUE( + RedactStructRecursively(path_pieces.cbegin(), path_pieces.cend(), &message_struct).ok()); + + // Verify that the field "level2" has been replaced with an empty Struct + const auto& level1_field = message_struct.fields().at("level1"); + EXPECT_TRUE(level1_field.has_struct_value()); + const auto& level2_field = level1_field.struct_value().fields().at("level2"); + EXPECT_TRUE(level2_field.has_struct_value()); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_MissingIntermediateField) { + Struct message_struct = CreateNestedStruct({"level1"}, "value"); + std::vector path_pieces = {"level1", "level2"}; + EXPECT_TRUE( + RedactStructRecursively(path_pieces.cbegin(), path_pieces.cend(), &message_struct).ok()); + + // Verify that "level2" field is created as an empty Struct + const auto& level1_field = message_struct.fields().at("level1"); + EXPECT_TRUE(level1_field.has_struct_value()); + const auto& level2_field = level1_field.struct_value().fields().at("level2"); + EXPECT_TRUE(level2_field.has_struct_value()); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_EmptyPathPiece) { + Struct message_struct = CreateNestedStruct({"level1", "level2"}, "value"); + std::vector path_pieces = {"level1", ""}; + EXPECT_EQ(RedactStructRecursively(path_pieces.cbegin(), path_pieces.cend(), &message_struct), + absl::InvalidArgumentError("path piece cannot be empty.")); +} + +TEST_F(AuditLoggingUtilTest, RedactStructRecursively_NullptrMessageStruct) { + std::vector path_pieces = {"level1"}; + EXPECT_EQ(RedactStructRecursively(path_pieces.cbegin(), path_pieces.cend(), nullptr), + absl::InvalidArgumentError("message_struct cannot be nullptr.")); +} + +TEST_F(AuditLoggingUtilTest, IsMessageFieldPathPresent_EmptyPath) { + EXPECT_EQ( + IsMessageFieldPathPresent(*request_type_, type_finder_, "", test_request_raw_proto_).status(), + absl::InvalidArgumentError("Field path cannot be empty.")); +} + +TEST_F(AuditLoggingUtilTest, IsMessageFieldPathPresent_EmptyType) { + Type empty_type; + EXPECT_EQ( + IsMessageFieldPathPresent(empty_type, type_finder_, "id", test_request_raw_proto_).status(), + absl::InvalidArgumentError("Cannot find field 'id' in '' message.")); +} + +TEST_F(AuditLoggingUtilTest, IsMessageFieldPathPresent_InvalidPath) { + EXPECT_EQ(IsMessageFieldPathPresent(*request_type_, type_finder_, "invalid_path", + test_request_raw_proto_) + .status(), + absl::InvalidArgumentError( + "Cannot find field 'invalid_path' in 'logging.TestRequest' message.")); +} + +TEST_F(AuditLoggingUtilTest, IsMessageFieldPathPresent_ValidPath) { + EXPECT_TRUE( + IsMessageFieldPathPresent(*request_type_, type_finder_, "bucket", test_request_raw_proto_) + .status() + .ok()); +} + +TEST_F(AuditLoggingUtilTest, IsMessageFieldPathPresent_NotMessageField) { + EXPECT_EQ(IsMessageFieldPathPresent(*request_type_, type_finder_, "repeated_strings", + test_request_raw_proto_) + .status(), + absl::InvalidArgumentError("Field 'repeated_strings' is not a message type field.")); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_bytes) { + EXPECT_EQ(3, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("bucket.objects"), test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, FindSingularLastValue_SingleStringField) { + Field field; + field.set_name("id"); + field.set_number(1); + field.set_kind(Field::TYPE_INT64); + + std::string data = "123445"; + auto result = FindSingularLastValue( + &field, &test_request_raw_proto_.CreateCodedInputStreamWrapper()->Get()); + ASSERT_TRUE(result.ok()); + EXPECT_EQ(result.value(), ""); +} + +TEST_F(AuditLoggingUtilTest, FindSingularLastValue_RepeatedStringField) { + Field field; + field.set_name("repeated_strings"); + field.set_number(3); + field.set_kind(Field::TYPE_STRING); + field.set_cardinality(Field::CARDINALITY_REPEATED); + + std::string data = "repeated-string-0"; + auto result = FindSingularLastValue( + &field, &test_request_raw_proto_.CreateCodedInputStreamWrapper()->Get()); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(result.value(), "repeated-string-0"); +} + +TEST_F(AuditLoggingUtilTest, FindSingularLastValue_RepeatedMessageField) { + Field field; + field.set_name("bucket"); + field.set_number(2); + field.set_kind(Field::TYPE_STRING); + + std::string data = "test-bucket"; + auto result = FindSingularLastValue( + &field, &test_request_raw_proto_.CreateCodedInputStreamWrapper()->Get()); + ASSERT_TRUE(result.ok()); + EXPECT_EQ( + result.value(), + "\n\vtest-bucket\x15\xCD\xCCL?\x1A\rtest-object-1\x1A\rtest-object-2\x1A\rtest-object-3"); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_string) { + EXPECT_EQ(1, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_strings"), + test_request_raw_proto_)); + EXPECT_EQ(2, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_strings"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_message) { + EXPECT_EQ(2, ExtractRepeatedFieldSize(*response_type_, type_finder_, GetFieldMaskWith("buckets"), + test_response_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_map) { + EXPECT_EQ(2, ExtractRepeatedFieldSize(*response_type_, type_finder_, + GetFieldMaskWith("sub_buckets"), test_response_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_enum) { + EXPECT_EQ(4, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_enum"), test_request_raw_proto_)); + EXPECT_EQ(4, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_enum"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_double) { + EXPECT_EQ(1, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_double"), test_request_raw_proto_)); + EXPECT_EQ(1, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_double"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_float) { + EXPECT_EQ(2, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_float"), test_request_raw_proto_)); + EXPECT_EQ(2, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_float"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_int64) { + EXPECT_EQ(3, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_int64"), test_request_raw_proto_)); + EXPECT_EQ(3, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_int64"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_uint64) { + EXPECT_EQ(4, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_uint64"), test_request_raw_proto_)); + EXPECT_EQ(4, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_uint64"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_int32) { + EXPECT_EQ(5, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_int32"), test_request_raw_proto_)); + EXPECT_EQ(5, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_int32"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_fixed64) { + EXPECT_EQ(6, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_fixed64"), + test_request_raw_proto_)); + EXPECT_EQ(6, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_fixed64"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_fixed32) { + EXPECT_EQ(7, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_fixed32"), + test_request_raw_proto_)); + EXPECT_EQ(7, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_fixed32"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_bool) { + EXPECT_EQ(5, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_bool"), test_request_raw_proto_)); + + EXPECT_EQ(5, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_bool"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_uint32) { + EXPECT_EQ(8, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_uint32"), test_request_raw_proto_)); + EXPECT_EQ(8, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_uint32"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_sfixed64) { + EXPECT_EQ(6, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_sfixed64"), + test_request_raw_proto_)); + EXPECT_EQ(6, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_sfixed64"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_sfixed32) { + EXPECT_EQ(7, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_sfixed32"), + test_request_raw_proto_)); + EXPECT_EQ(7, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_sfixed32"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_sint32) { + EXPECT_EQ(5, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_sint32"), test_request_raw_proto_)); + EXPECT_EQ(5, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_sint32"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_sint64) { + EXPECT_EQ(6, + ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_sint64"), test_request_raw_proto_)); + EXPECT_EQ(6, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("proto2_message.repeated_sint64"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_OK_DefaultValue) { + test_request_proto_.clear_repeated_strings(); + test_request_raw_proto_ = CordMessageData(test_request_proto_.SerializeAsCord()); + EXPECT_EQ(0, ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("repeated_strings"), + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_EmptyPath) { + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, GetFieldMaskWith(""), + test_request_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_NonRepeatedField) { + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, GetFieldMaskWith("bucket.ratio"), + test_request_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_UnknownField) { + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("bucket.unknown"), test_request_raw_proto_), + 0); + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, GetFieldMaskWith("unknown"), + test_request_raw_proto_), + 0); + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("unknown1.unknown2"), + test_request_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_NonLeafPrimitiveTypeField) { + EXPECT_LT(ExtractRepeatedFieldSize(*request_type_, type_finder_, + GetFieldMaskWith("bucket.name.unknown"), + test_request_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_NonLeafMapField) { + EXPECT_LT(ExtractRepeatedFieldSize(*response_type_, type_finder_, + GetFieldMaskWith("sub_buckets.objects"), + test_response_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_NonLeafRepeatedField) { + EXPECT_LT(ExtractRepeatedFieldSize(*response_type_, type_finder_, + GetFieldMaskWith("buckets.name"), test_response_raw_proto_), + 0); + EXPECT_LT(ExtractRepeatedFieldSize(*response_type_, type_finder_, + GetFieldMaskWith("buckets.objects"), test_response_raw_proto_), + 0); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_Error_NullptrFieldMask) { + EXPECT_GT( + 0, ExtractRepeatedFieldSize(*request_type_, type_finder_, nullptr, test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractRepeatedFieldSize_EmptyFieldMask) { + FieldMask field_mask; + EXPECT_GT(0, ExtractRepeatedFieldSize(*request_type_, type_finder_, &field_mask_, + test_request_raw_proto_)); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_OK) { + EXPECT_THAT( + ExtractStringFieldValue(*request_type_, type_finder_, "bucket.name", test_request_raw_proto_), + IsOkAndHolds("test-bucket")); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_OK_DefaultValue) { + test_request_proto_.mutable_bucket()->clear_name(); + test_request_raw_proto_ = CordMessageData(test_request_proto_.SerializeAsCord()); + EXPECT_THAT( + ExtractStringFieldValue(*request_type_, type_finder_, "bucket.name", test_request_raw_proto_), + IsOkAndHolds("")); + + test_request_proto_.clear_bucket(); + test_request_raw_proto_ = CordMessageData(test_request_proto_.SerializeAsCord()); + EXPECT_THAT( + ExtractStringFieldValue(*request_type_, type_finder_, "bucket.name", test_request_raw_proto_), + IsOkAndHolds("")); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_Error_EmptyPath) { + EXPECT_THAT(ExtractStringFieldValue(*request_type_, type_finder_, "", test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_Error_UnknownField) { + EXPECT_THAT(ExtractStringFieldValue(*request_type_, type_finder_, "bucket.unknown", + test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); + + EXPECT_THAT( + ExtractStringFieldValue(*request_type_, type_finder_, "unknown", test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); + + EXPECT_THAT(ExtractStringFieldValue(*request_type_, type_finder_, "unknown1.unknown2", + test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_Error_RepeatedStringLeafNode) { + EXPECT_THAT(ExtractStringFieldValue(*request_type_, type_finder_, "repeated_strings", + test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_Error_NonStringLeafNode) { + EXPECT_THAT(ExtractStringFieldValue(*request_type_, type_finder_, "bucket.ratio", + test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); + + EXPECT_THAT(ExtractStringFieldValue(*response_type_, type_finder_, "sub_buckets", + test_response_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(AuditLoggingUtilTest, ExtractStringFieldValue_Error_InvalidTypeFinder) { + auto invalid_type_finder = [](absl::string_view /*type_url*/) { return nullptr; }; + + EXPECT_THAT(ExtractStringFieldValue(*request_type_, invalid_type_finder, "bucket.ratio", + test_request_raw_proto_), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST(StructUtilTest, RedactPaths_Basic) { + std::string proto_struct_string = "fields {" + " key: \"nested\"" + " value {" + " struct_value {" + " fields {" + " key: \"deeper_nest\"" + " value {" + " struct_value: {" + " fields {" + " key: \"nice_field\"" + " value {" + " string_value: \"nice value\"" + " }" + " }" + " }" + " }" + " }" + " }" + " }" + "}"; + Struct proto_struct; + CHECK(Protobuf::TextFormat::ParseFromString(proto_struct_string, &proto_struct)); + + std::vector paths_to_redact = {"nested.deeper_nest"}; + RedactPaths(paths_to_redact, &proto_struct); + + std::string expected_struct_string = "fields {" + " key: \"nested\"" + " value {" + " struct_value {" + " fields {" + " key: \"deeper_nest\"" + " value {" + " struct_value: {}" + " }" + " }" + " }" + " }" + "}"; + Struct expected_struct; + CHECK(Protobuf::TextFormat::ParseFromString(expected_struct_string, &expected_struct)); + EXPECT_TRUE(Protobuf::util::MessageDifferencer::Equals(expected_struct, proto_struct)); +} + +TEST(StructUtilTest, RedactPaths_HandlesOneOfFields) { + std::string proto_struct_string = "fields {" + " key: \"nested_value\"" + " value {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 123" + " }" + " }" + " }" + " }" + "}"; + Struct proto_struct; + CHECK(Protobuf::TextFormat::ParseFromString(proto_struct_string, &proto_struct)); + + std::vector paths_to_redact = {"nested_value"}; + RedactPaths(paths_to_redact, &proto_struct); + + std::string expected_struct_string = "fields {" + " key: \"nested_value\"" + " value {" + " struct_value {}" + " }" + "}"; + Struct expected_struct; + CHECK(Protobuf::TextFormat::ParseFromString(expected_struct_string, &expected_struct)); + EXPECT_TRUE(Protobuf::util::MessageDifferencer::Equals(expected_struct, proto_struct)); +} + +TEST(StructUtilTest, RedactPaths_AllowsRepeatedLeafMessageType) { + std::string proto_struct_string = "fields {" + " key: \"repeated_message_field\"" + " value {" + " list_value {" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 123" + " }" + " }" + " }" + " }" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 456" + " }" + " }" + " }" + " }" + " }" + " }" + "}"; + Struct proto_struct; + CHECK(Protobuf::TextFormat::ParseFromString(proto_struct_string, &proto_struct)); + + std::vector paths_to_redact = {"repeated_message_field"}; + RedactPaths(paths_to_redact, &proto_struct); + + std::string expected_struct_string = "fields {" + " key: \"repeated_message_field\"" + " value {" + " list_value {" + " values {" + " struct_value {}" + " }" + " values {" + " struct_value {}" + " }" + " }" + " }" + "}"; + Struct expected_struct; + CHECK(Protobuf::TextFormat::ParseFromString(expected_struct_string, &expected_struct)); + EXPECT_TRUE(Protobuf::util::MessageDifferencer::Equals(expected_struct, proto_struct)); +} + +TEST(StructUtilTest, RedactPaths_AllowsRepeatedNonLeafMessageType) { + std::string proto_struct_string = "fields {" + " key: \"repeated_message_field\"" + " value {" + " list_value {" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 123" + " }" + " }" + " fields {" + " key: \"deeper_nest\"" + " value {" + " struct_value {" + " fields {" + " key: \"nice_field\"" + " value: {" + " string_value: \"nice value\"" + " }" + " }" + " }" + " }" + " }" + " }" + " }" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 456" + " }" + " }" + " }" + " }" + " }" + " }" + "}"; + Struct proto_struct; + CHECK(Protobuf::TextFormat::ParseFromString(proto_struct_string, &proto_struct)); + + std::vector paths_to_redact = {"repeated_message_field.deeper_nest"}; + RedactPaths(paths_to_redact, &proto_struct); + + std::string expected_struct_string = "fields {" + " key: \"repeated_message_field\"" + " value {" + " list_value {" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 123" + " }" + " }" + " fields {" + " key: \"deeper_nest\"" + " value {" + " struct_value {}" + " }" + " }" + " }" + " }" + " values {" + " struct_value {" + " fields {" + " key: \"uint32_field\"" + " value {" + " number_value: 456" + " }" + " }" + " }" + " }" + " }" + " }" + "}"; + Struct expected_struct; + CHECK(Protobuf::TextFormat::ParseFromString(expected_struct_string, &expected_struct)); + EXPECT_TRUE(Protobuf::util::MessageDifferencer::Equals(expected_struct, proto_struct)); +} + +struct ResourceNameTestCase { + std::string test_name; + std::string resource_name; + std::string expected_location; +}; + +class ExtractLocationIdFromResourceNameTest + : public ::testing::TestWithParam {}; + +TEST_P(ExtractLocationIdFromResourceNameTest, Test) { + // Empty resource name - should return empty string. + const ResourceNameTestCase& params = GetParam(); + EXPECT_EQ(ExtractLocationIdFromResourceName(params.resource_name), params.expected_location); +} + +INSTANTIATE_TEST_SUITE_P( + ExtractLocationIdFromResourceNameTests, ExtractLocationIdFromResourceNameTest, + ValuesIn({ + {"EmptyResource", "", ""}, + {"NoLocation", "projects/123/buckets/abc", ""}, + {"LocationSubstring", "my_locations/123/frw1/fw1", ""}, + {"MissingLocationValue", "projects/123/buckets/abc/locations/", ""}, + {"EmptyLocationValue", "projects/123/locations//buckets/abc", ""}, + {"LocationInMiddle", "projects/123/locations/456/buckets/abc", "456"}, + {"LocationAtEnd", "projects/123/locations/456", "456"}, + {"LocationAtStartQualified", "//locations/123/", "123"}, + {"LocationOnly", "locations/123", "123"}, + {"LocationAtStartWithMore", "locations/123/frwl/fw1", "123"}, + {"RegionSubstring", "my_regions/123/frw1/fw1", ""}, + {"MissingRegionValue", "projects/123/buckets/abc/regions/", ""}, + {"EmptyRegionValue", "projects/123/regions//buckets/abc", ""}, + {"RegionInMiddle", "projects/123/regions/456/buckets/abc", "456"}, + {"RegionAtEnd", "projects/123/regions/456", "456"}, + {"RegionAtStartQualified", "//regions/123/", "123"}, + {"RegionOnly", "regions/123", "123"}, + {"RegionAtStartWithMore", "regions/123/frwl/fw1", "123"}, + }), + [](const ::testing::TestParamInfo& info) { + return info.param.test_name; + }); + +} // namespace +} // namespace ProtoMessageLogging +} // namespace HttpFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.yaml b/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.yaml new file mode 100644 index 000000000000..f8c0fac6402b --- /dev/null +++ b/test/extensions/filters/http/proto_message_logging/logging_util/logging_util_test.yaml @@ -0,0 +1,23 @@ +type: google.api.Service +config_version: 3 +name: audit_logging_util_test.googleapis.com +title: Audit Logging Util Test API +apis: +- name: proto_processing_lib.proto_scrubber.testing.AuditLoggingUtilTestService + +documentation: + overview: | + (== suppress_warning quota-presence ==) + (== suppress_warning usage_manager-presence ==) + (== suppress_warning http-rest ==) + (== suppress_warning versioning-http-version-prefix ==) + (== suppress_warning documentation-presence ==) + (== suppress_warning legacy-contacts ==) + (== suppress_warning versioning-config ==) + summary: + Audit Logging Util Test + +backend: + rules: + - selector: '*' + address: diff --git a/test/extensions/filters/http/rate_limit_quota/integration_test.cc b/test/extensions/filters/http/rate_limit_quota/integration_test.cc index d342e3aca00c..ec4e45a89113 100644 --- a/test/extensions/filters/http/rate_limit_quota/integration_test.cc +++ b/test/extensions/filters/http/rate_limit_quota/integration_test.cc @@ -50,13 +50,18 @@ class RateLimitQuotaIntegrationTest } } - void initializeConfig(ConfigOption config_option = {}) { - config_helper_.addConfigModifier([this, config_option]( + void initializeConfig(ConfigOption config_option = {}, const std::string& log_format = "") { + config_helper_.addConfigModifier([this, config_option, log_format]( envoy::config::bootstrap::v3::Bootstrap& bootstrap) { // Ensure "HTTP2 with no prior knowledge." Necessary for gRPC and for headers ConfigHelper::setHttp2( *(bootstrap.mutable_static_resources()->mutable_clusters()->Mutable(0))); + // Enable access logging for testing dynamic metadata. + if (!log_format.empty()) { + HttpIntegrationTest::useAccessLog(log_format); + } + // Clusters for ExtProc gRPC servers, starting by copying an existing cluster for (size_t i = 0; i < grpc_upstreams_.size(); ++i) { auto* server_cluster = bootstrap.mutable_static_resources()->add_clusters(); @@ -298,6 +303,58 @@ TEST_P(RateLimitQuotaIntegrationTest, BasicFlowResponseMatched) { EXPECT_EQ(response_->headers().getStatusValue(), "200"); } +TEST_P(RateLimitQuotaIntegrationTest, TestBasicMetadataLogging) { + initializeConfig({}, "Whole Bucket " + "ID=%DYNAMIC_METADATA(envoy.extensions.http_filters.rate_" + "limit_quota.bucket)%\n" + "Name=%DYNAMIC_METADATA(envoy.extensions.http_filters.rate_" + "limit_quota.bucket:name)%"); + HttpIntegrationTest::initialize(); + absl::flat_hash_map custom_headers = {{"environment", "staging"}, + {"group", "envoy"}}; + // Send downstream client request to upstream. + sendClientRequest(&custom_headers); + + // Start the gRPC stream to RLQS server. + ASSERT_TRUE(grpc_upstreams_[0]->waitForHttpConnection(*dispatcher_, rlqs_connection_)); + ASSERT_TRUE(rlqs_connection_->waitForNewStream(*dispatcher_, rlqs_stream_)); + envoy::service::rate_limit_quota::v3::RateLimitQuotaUsageReports reports; + ASSERT_TRUE(rlqs_stream_->waitForGrpcMessage(*dispatcher_, reports)); + rlqs_stream_->startGrpcStream(); + + // Build the response whose bucket ID matches the sent report. + envoy::service::rate_limit_quota::v3::RateLimitQuotaResponse rlqs_response; + custom_headers.insert({"name", "prod"}); + auto* bucket_action = rlqs_response.add_bucket_action(); + for (const auto& [key, value] : custom_headers) { + (*bucket_action->mutable_bucket_id()->mutable_bucket()).insert({key, value}); + } + // Send the response from RLQS server. + rlqs_stream_->sendGrpcMessage(rlqs_response); + + // Handle the request received by upstream. + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, false); + upstream_request_->encodeData(100, true); + + // Verify the response to downstream. + ASSERT_TRUE(response_->waitForEndStream()); + EXPECT_TRUE(response_->complete()); + EXPECT_EQ(response_->headers().getStatusValue(), "200"); + + std::string log_output0 = + HttpIntegrationTest::waitForAccessLog(HttpIntegrationTest::access_log_name_, 0, true); + EXPECT_THAT(log_output0, testing::HasSubstr("Whole Bucket ID")); + EXPECT_THAT(log_output0, testing::HasSubstr("\"name\":\"prod\"")); + EXPECT_THAT(log_output0, testing::HasSubstr("\"group\":\"envoy\"")); + EXPECT_THAT(log_output0, testing::HasSubstr("\"environment\":\"staging\"")); + std::string log_output1 = + HttpIntegrationTest::waitForAccessLog(HttpIntegrationTest::access_log_name_, 1, true); + EXPECT_THAT(log_output1, testing::HasSubstr("Name=prod")); +} + TEST_P(RateLimitQuotaIntegrationTest, BasicFlowMultiSameRequest) { initializeConfig(); HttpIntegrationTest::initialize(); @@ -652,6 +709,95 @@ TEST_P(RateLimitQuotaIntegrationTest, BasicFlowPeriodicalReport) { } } +TEST_P(RateLimitQuotaIntegrationTest, BasicFlowPeriodicalReportWithStreamClosed) { + initializeConfig(); + HttpIntegrationTest::initialize(); + absl::flat_hash_map custom_headers = {{"environment", "staging"}, + {"group", "envoy"}}; + // Send downstream client request to upstream. + sendClientRequest(&custom_headers); + + ASSERT_TRUE(grpc_upstreams_[0]->waitForHttpConnection(*dispatcher_, rlqs_connection_)); + ASSERT_TRUE(rlqs_connection_->waitForNewStream(*dispatcher_, rlqs_stream_)); + // reports should be built in filter.cc + envoy::service::rate_limit_quota::v3::RateLimitQuotaUsageReports reports; + ASSERT_TRUE(rlqs_stream_->waitForGrpcMessage(*dispatcher_, reports)); + + // Verify the usage report content. + ASSERT_THAT(reports.bucket_quota_usages_size(), 1); + const auto& usage = reports.bucket_quota_usages(0); + // We only send single downstream client request and it is allowed. + EXPECT_EQ(usage.num_requests_allowed(), 1); + EXPECT_EQ(usage.num_requests_denied(), 0); + // It is first report so the time_elapsed is 0. + EXPECT_EQ(Protobuf::util::TimeUtil::DurationToSeconds(usage.time_elapsed()), 0); + + rlqs_stream_->startGrpcStream(); + + // Build the response. + envoy::service::rate_limit_quota::v3::RateLimitQuotaResponse rlqs_response; + absl::flat_hash_map custom_headers_cpy = custom_headers; + custom_headers_cpy.insert({"name", "prod"}); + auto* bucket_action = rlqs_response.add_bucket_action(); + + for (const auto& [key, value] : custom_headers_cpy) { + (*bucket_action->mutable_bucket_id()->mutable_bucket()).insert({key, value}); + } + rlqs_stream_->sendGrpcMessage(rlqs_response); + + // Handle the request received by upstream. + ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_)); + ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_)); + ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_)); + upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, false); + upstream_request_->encodeData(100, true); + + // Verify the response to downstream. + ASSERT_TRUE(response_->waitForEndStream()); + EXPECT_TRUE(response_->complete()); + EXPECT_EQ(response_->headers().getStatusValue(), "200"); + + // ValidMatcherConfig. + int report_interval_sec = 60; + // Trigger the report periodically. + for (int i = 0; i < 6; ++i) { + if (i == 2) { + // Close the stream. + rlqs_stream_->finishGrpcStream(Grpc::Status::Ok); + } + + // Advance the time by report_interval. + simTime().advanceTimeWait(std::chrono::milliseconds(report_interval_sec * 1000)); + + // Only perform rlqs server check and response before stream is remotely closed. + if (i < 2) { + // Checks that the rate limit server has received the periodical reports. + ASSERT_TRUE(rlqs_stream_->waitForGrpcMessage(*dispatcher_, reports)); + + // Verify the usage report content. + ASSERT_THAT(reports.bucket_quota_usages_size(), 1); + const auto& usage = reports.bucket_quota_usages(0); + // Report only represents the usage since last report. + // In the periodical report case here, the number of request allowed and denied is 0 since no + // new requests comes in. + EXPECT_EQ(usage.num_requests_allowed(), 0); + EXPECT_EQ(usage.num_requests_denied(), 0); + // time_elapsed equals to periodical reporting interval. + EXPECT_EQ(Protobuf::util::TimeUtil::DurationToSeconds(usage.time_elapsed()), + report_interval_sec); + + // Build the rlqs server response. + envoy::service::rate_limit_quota::v3::RateLimitQuotaResponse rlqs_response2; + auto* bucket_action2 = rlqs_response2.add_bucket_action(); + + for (const auto& [key, value] : custom_headers_cpy) { + (*bucket_action2->mutable_bucket_id()->mutable_bucket()).insert({key, value}); + } + rlqs_stream_->sendGrpcMessage(rlqs_response2); + } + } +} + // RLQS filter is operating in non-blocking mode now, this test could be flaky until the stats are // added to make the test behavior deterministic. (e.g., wait for stats in the test). // Disable the test for now. diff --git a/test/extensions/filters/http/ratelimit/ratelimit_test.cc b/test/extensions/filters/http/ratelimit/ratelimit_test.cc index 8207ba087fab..6caa81e8eb5f 100644 --- a/test/extensions/filters/http/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/http/ratelimit/ratelimit_test.cc @@ -3,11 +3,13 @@ #include #include "envoy/extensions/filters/http/ratelimit/v3/rate_limit.pb.h" +#include "envoy/stream_info/stream_info.h" #include "source/common/buffer/buffer_impl.h" #include "source/common/common/empty_string.h" #include "source/common/http/context_impl.h" #include "source/common/http/headers.h" +#include "source/common/stream_info/uint32_accessor_impl.h" #include "source/extensions/filters/http/ratelimit/ratelimit.h" #include "test/extensions/filters/common/ratelimit/mocks.h" @@ -257,6 +259,53 @@ TEST_F(HttpRateLimitFilterTest, OkResponse) { 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromStatName(ratelimit_ok_).value()); } +TEST_F(HttpRateLimitFilterTest, OkResponseWithAdditionalHitsAddend) { + setUpTest(filter_config_); + InSequence s; + + filter_callbacks_.stream_info_.filter_state_->setData( + "envoy.ratelimit.hits_addend", std::make_unique(5), + StreamInfo::FilterState::StateType::ReadOnly); + EXPECT_CALL(filter_callbacks_.route_->route_entry_.rate_limit_policy_, getApplicableRateLimit(0)); + + EXPECT_CALL(route_rate_limit_, populateDescriptors(_, _, _, _)) + .WillOnce(SetArgReferee<0>(descriptor_)); + + EXPECT_CALL(filter_callbacks_.route_->virtual_host_.rate_limit_policy_, + getApplicableRateLimit(0)); + + EXPECT_CALL(*client_, limit(_, "foo", + testing::ContainerEq(std::vector{ + {{{"descriptor_key", "descriptor_value"}}}}), + _, _, 5)) + .WillOnce( + WithArgs<0>(Invoke([&](Filters::Common::RateLimit::RequestCallbacks& callbacks) -> void { + request_callbacks_ = &callbacks; + }))); + + request_headers_.addCopy(Http::Headers::get().RequestId, "requestid"); + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(request_headers_, false)); + Http::MetadataMap metadata_map{{"metadata", "metadata"}}; + EXPECT_EQ(Http::FilterMetadataStatus::Continue, filter_->decodeMetadata(metadata_map)); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndWatermark, filter_->decodeData(data_, false)); + EXPECT_EQ(Http::FilterTrailersStatus::StopIteration, filter_->decodeTrailers(request_trailers_)); + EXPECT_EQ(Http::Filter1xxHeadersStatus::Continue, filter_->encode1xxHeaders(response_headers_)); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(response_headers_, false)); + EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->encodeData(response_data_, false)); + EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(response_trailers_)); + + EXPECT_CALL(filter_callbacks_, continueDecoding()); + EXPECT_CALL(filter_callbacks_.stream_info_, + setResponseFlag(StreamInfo::CoreResponseFlag::RateLimited)) + .Times(0); + request_callbacks_->complete(Filters::Common::RateLimit::LimitStatus::OK, nullptr, nullptr, + nullptr, "", nullptr); + + EXPECT_EQ( + 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromStatName(ratelimit_ok_).value()); +} + TEST_F(HttpRateLimitFilterTest, OkResponseWithHeaders) { setUpTest(filter_config_); InSequence s; @@ -1667,6 +1716,18 @@ TEST_F(HttpRateLimitFilterTest, StatsWithPrefix) { EXPECT_EQ("request_rate_limited", filter_callbacks_.details()); } +TEST(ObjectFactory, HitsAddend) { + const std::string name = "envoy.ratelimit.hits_addend"; + auto* factory = + Registry::FactoryRegistry::getFactory(name); + ASSERT_NE(nullptr, factory); + EXPECT_EQ(name, factory->name()); + const std::string hits_addend = std::to_string(1234); + auto object = factory->createFromBytes(hits_addend); + ASSERT_NE(nullptr, object); + EXPECT_EQ(hits_addend, object->serializeAsString()); +} + } // namespace } // namespace RateLimitFilter } // namespace HttpFilters diff --git a/test/extensions/filters/http/rbac/rbac_filter_test.cc b/test/extensions/filters/http/rbac/rbac_filter_test.cc index 2d772457a176..3877ab4046bc 100644 --- a/test/extensions/filters/http/rbac/rbac_filter_test.cc +++ b/test/extensions/filters/http/rbac/rbac_filter_test.cc @@ -576,6 +576,134 @@ TEST_F(RoleBasedAccessControlFilterTest, RouteLocalOverride) { checkAccessLogMetadata(LogResult::Undecided); } +TEST_F(RoleBasedAccessControlFilterTest, RouteLocalOverrideDynamicMetadataStats) { + setupPolicy(envoy::config::rbac::v3::RBAC::DENY, "original_rbac_rules_prefix_"); + + setDestinationPort(123); + setMetadata(); + + // Set up an allow route_config that overrides the deny policy. + envoy::extensions::filters::http::rbac::v3::RBACPerRoute route_config; + route_config.mutable_rbac()->mutable_rules()->set_action(envoy::config::rbac::v3::RBAC::ALLOW); + route_config.mutable_rbac()->mutable_shadow_rules()->set_action( + envoy::config::rbac::v3::RBAC::ALLOW); + route_config.mutable_rbac()->set_rules_stat_prefix("override_rules_stat_prefix_"); + route_config.mutable_rbac()->set_shadow_rules_stat_prefix("override_shadow_rules_stat_prefix_"); + + envoy::config::rbac::v3::Policy policy; + auto policy_rules = policy.add_permissions()->mutable_or_rules(); + policy_rules->add_rules()->set_destination_port(123); + policy.add_principals()->set_any(true); + + envoy::config::rbac::v3::Policy shadow_policy; + auto shadow_policy_rules = shadow_policy.add_permissions()->mutable_or_rules(); + shadow_policy_rules->add_rules()->set_destination_port(123); + shadow_policy.add_principals()->set_any(true); + + (*route_config.mutable_rbac()->mutable_rules()->mutable_policies())["foobar"] = policy; + (*route_config.mutable_rbac()->mutable_shadow_rules()->mutable_policies())["foobar"] = + shadow_policy; + NiceMock factory_context; + NiceMock engine{route_config.rbac().rules(), factory_context}; + NiceMock per_route_config_{route_config, + context_}; + + EXPECT_CALL(engine, handleAction(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(per_route_config_, engine()).WillRepeatedly(ReturnRef(engine)); + + EXPECT_CALL(*callbacks_.route_, mostSpecificPerFilterConfig(_)) + .WillRepeatedly(Return(&per_route_config_)); + + // Filter iteration should continue since the route-specific policy is ALLOW + // and there are enforced and shadow rules. + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers_, true)); + ASSERT_TRUE(req_info_.dynamicMetadata().filter_metadata().contains("envoy.filters.http.rbac")); + auto filter_meta = req_info_.dynamicMetadata().filter_metadata().at("envoy.filters.http.rbac"); + + // We expect the route-specific rules and prefix to be used for the enforced + // engine and the shadow rules and prefix to be used for the shadow engine. + ASSERT_TRUE(filter_meta.fields().contains("override_rules_stat_prefix_enforced_engine_result")); + EXPECT_EQ( + "allowed", + filter_meta.fields().at("override_rules_stat_prefix_enforced_engine_result").string_value()); + ASSERT_TRUE( + filter_meta.fields().contains("override_rules_stat_prefix_enforced_effective_policy_id")); + EXPECT_EQ("foobar", filter_meta.fields() + .at("override_rules_stat_prefix_enforced_effective_policy_id") + .string_value()); + + ASSERT_TRUE( + filter_meta.fields().contains("override_shadow_rules_stat_prefix_shadow_engine_result")); + EXPECT_EQ("allowed", filter_meta.fields() + .at("override_shadow_rules_stat_prefix_shadow_engine_result") + .string_value()); + ASSERT_TRUE(filter_meta.fields().contains( + "override_shadow_rules_stat_prefix_shadow_effective_policy_id")); + EXPECT_EQ("foobar", filter_meta.fields() + .at("override_shadow_rules_stat_prefix_shadow_effective_policy_id") + .string_value()); +} + +TEST_F(RoleBasedAccessControlFilterTest, NoRouteLocalOverrideDynamicMetadataStatsEmpty) { + setupPolicy(envoy::config::rbac::v3::RBAC::DENY, "rules_stat_prefix_"); + + setDestinationPort(123); + setMetadata(); + + // Set up an allow route_config that overrides the deny policy. But do not set up stat prefixes. + envoy::extensions::filters::http::rbac::v3::RBACPerRoute route_config; + route_config.mutable_rbac()->mutable_rules()->set_action(envoy::config::rbac::v3::RBAC::ALLOW); + route_config.mutable_rbac()->mutable_shadow_rules()->set_action( + envoy::config::rbac::v3::RBAC::ALLOW); + + envoy::config::rbac::v3::Policy policy; + auto policy_rules = policy.add_permissions()->mutable_or_rules(); + policy_rules->add_rules()->set_destination_port(123); + policy.add_principals()->set_any(true); + + envoy::config::rbac::v3::Policy shadow_policy; + auto shadow_policy_rules = shadow_policy.add_permissions()->mutable_or_rules(); + shadow_policy_rules->add_rules()->set_destination_port(123); + shadow_policy.add_principals()->set_any(true); + + (*route_config.mutable_rbac()->mutable_rules()->mutable_policies())["foobar"] = policy; + (*route_config.mutable_rbac()->mutable_shadow_rules()->mutable_policies())["foobar"] = + shadow_policy; + NiceMock factory_context; + NiceMock engine{route_config.rbac().rules(), factory_context}; + NiceMock per_route_config_{route_config, + context_}; + + EXPECT_CALL(engine, handleAction(_, _, _, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(per_route_config_, engine()).WillRepeatedly(ReturnRef(engine)); + + EXPECT_CALL(*callbacks_.route_, mostSpecificPerFilterConfig(_)) + .WillRepeatedly(Return(&per_route_config_)); + + // Filter iteration should continue since the route-specific policy is ALLOW and there are + // enforced and shadow rules. + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers_, true)); + ASSERT_TRUE(req_info_.dynamicMetadata().filter_metadata().contains("envoy.filters.http.rbac")); + auto filter_meta = req_info_.dynamicMetadata().filter_metadata().at("envoy.filters.http.rbac"); + + // We expect the base rules and prefix to be used since no route-specific stat was set up. + ASSERT_TRUE(filter_meta.fields().contains("rules_stat_prefix_enforced_engine_result")); + EXPECT_EQ("allowed", + filter_meta.fields().at("rules_stat_prefix_enforced_engine_result").string_value()); + ASSERT_TRUE(filter_meta.fields().contains("rules_stat_prefix_enforced_effective_policy_id")); + EXPECT_EQ( + "foobar", + filter_meta.fields().at("rules_stat_prefix_enforced_effective_policy_id").string_value()); + + ASSERT_TRUE(filter_meta.fields().contains("shadow_rules_prefix_shadow_engine_result")); + EXPECT_EQ("allowed", + filter_meta.fields().at("shadow_rules_prefix_shadow_engine_result").string_value()); + ASSERT_TRUE(filter_meta.fields().contains("shadow_rules_prefix_shadow_effective_policy_id")); + EXPECT_EQ( + "foobar", + filter_meta.fields().at("shadow_rules_prefix_shadow_effective_policy_id").string_value()); +} + TEST_F(RoleBasedAccessControlFilterTest, RouteLocalOverrideWithPerRuleStats) { setupPolicy(envoy::config::rbac::v3::RBAC::ALLOW); diff --git a/test/extensions/filters/http/router/auto_sni_integration_test.cc b/test/extensions/filters/http/router/auto_sni_integration_test.cc index 325c64af38af..38d84bdb7949 100644 --- a/test/extensions/filters/http/router/auto_sni_integration_test.cc +++ b/test/extensions/filters/http/router/auto_sni_integration_test.cc @@ -9,6 +9,7 @@ #include "source/common/tls/server_ssl_socket.h" #include "test/integration/http_integration.h" +#include "test/test_common/utility.h" namespace Envoy { namespace { @@ -18,7 +19,8 @@ class AutoSniIntegrationTest : public testing::TestWithParamset_name("envoy.transport_sockets.tls"); cluster_config.mutable_transport_socket()->mutable_typed_config()->PackFrom(tls_context); }); + if (route_config != nullptr) { + config_helper_.addConfigModifier( + [route_config](envoy::extensions::filters::network::http_connection_manager::v3:: + HttpConnectionManager& hcm) { + auto* new_route_config = hcm.mutable_route_config(); + new_route_config->CopyFrom(*route_config); + }); + } HttpIntegrationTest::initialize(); } @@ -90,6 +100,141 @@ TEST_P(AutoSniIntegrationTest, BasicAutoSniTest) { EXPECT_STREQ("localhost", SSL_get_servername(ssl_socket->ssl(), TLSEXT_NAMETYPE_host_name)); } +TEST_P(AutoSniIntegrationTest, AutoSniTestWithHostRewrite) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + name: "foo" + route: + cluster: cluster_0 + host_rewrite_literal: foo + )EOF"; + envoy::config::route::v3::RouteConfiguration route_config; + TestUtility::loadFromYaml(yaml, route_config); + setup("", &route_config); + + codec_client_ = makeHttpConnection(lookupPort("http")); + const auto response_ = sendRequestAndWaitForResponse( + Http::TestRequestHeaderMapImpl{ + {":method", "GET"}, {":path", "/"}, {":scheme", "http"}, {":authority", "localhost"}}, + 0, default_response_headers_, 0); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response_->complete()); + + const Extensions::TransportSockets::Tls::SslHandshakerImpl* ssl_socket = + dynamic_cast( + fake_upstream_connection_->connection().ssl().get()); + EXPECT_STREQ("foo", SSL_get_servername(ssl_socket->ssl(), TLSEXT_NAMETYPE_host_name)); +} + +TEST_P(AutoSniIntegrationTest, AutoSniTestWithHostRewriteLegacy) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + name: "foo" + route: + cluster: cluster_0 + host_rewrite_literal: foo + )EOF"; + envoy::config::route::v3::RouteConfiguration route_config; + TestUtility::loadFromYaml(yaml, route_config); + config_helper_.addRuntimeOverride( + "envoy.reloadable_features.use_route_host_mutation_for_auto_sni_san", "false"); + setup("", &route_config); + codec_client_ = makeHttpConnection(lookupPort("http")); + const auto response_ = sendRequestAndWaitForResponse( + Http::TestRequestHeaderMapImpl{ + {":method", "GET"}, {":path", "/"}, {":scheme", "http"}, {":authority", "localhost"}}, + 0, default_response_headers_, 0); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response_->complete()); + + const Extensions::TransportSockets::Tls::SslHandshakerImpl* ssl_socket = + dynamic_cast( + fake_upstream_connection_->connection().ssl().get()); + EXPECT_STRNE("foo", SSL_get_servername(ssl_socket->ssl(), TLSEXT_NAMETYPE_host_name)); +} + +TEST_P(AutoSniIntegrationTest, AutoSniTestWithHostRewriteRegex) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + name: "foo" + route: + cluster: cluster_0 + host_rewrite_path_regex: + pattern: + regex: ".*" + substitution: "foo" + )EOF"; + envoy::config::route::v3::RouteConfiguration route_config; + TestUtility::loadFromYaml(yaml, route_config); + setup("", &route_config); + + codec_client_ = makeHttpConnection(lookupPort("http")); + const auto response_ = sendRequestAndWaitForResponse( + Http::TestRequestHeaderMapImpl{ + {":method", "GET"}, {":path", "/"}, {":scheme", "http"}, {":authority", "localhost"}}, + 0, default_response_headers_, 0); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response_->complete()); + + const Extensions::TransportSockets::Tls::SslHandshakerImpl* ssl_socket = + dynamic_cast( + fake_upstream_connection_->connection().ssl().get()); + EXPECT_STREQ("foo", SSL_get_servername(ssl_socket->ssl(), TLSEXT_NAMETYPE_host_name)); +} + +TEST_P(AutoSniIntegrationTest, AutoSniTestWithHostRewriteHeader) { + const std::string yaml = R"EOF( +virtual_hosts: +- name: local_service + domains: ["*"] + routes: + - match: + prefix: "/" + name: "foo" + route: + cluster: cluster_0 + host_rewrite_header: bar + )EOF"; + envoy::config::route::v3::RouteConfiguration route_config; + TestUtility::loadFromYaml(yaml, route_config); + setup("", &route_config); + + codec_client_ = makeHttpConnection(lookupPort("http")); + const auto response_ = + sendRequestAndWaitForResponse(Http::TestRequestHeaderMapImpl{{":method", "GET"}, + {":path", "/"}, + {":scheme", "http"}, + {":authority", "localhost"}, + {"bar", "foo"}}, + 0, default_response_headers_, 0); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response_->complete()); + + const Extensions::TransportSockets::Tls::SslHandshakerImpl* ssl_socket = + dynamic_cast( + fake_upstream_connection_->connection().ssl().get()); + EXPECT_STREQ("foo", SSL_get_servername(ssl_socket->ssl(), TLSEXT_NAMETYPE_host_name)); +} + TEST_P(AutoSniIntegrationTest, AutoSniWithAltHeaderNameTest) { setup("x-host"); codec_client_ = makeHttpConnection(lookupPort("http")); diff --git a/test/extensions/filters/http/thrift_to_metadata/filter_test.cc b/test/extensions/filters/http/thrift_to_metadata/filter_test.cc index 3153e5920b9c..c24be7992947 100644 --- a/test/extensions/filters/http/thrift_to_metadata/filter_test.cc +++ b/test/extensions/filters/http/thrift_to_metadata/filter_test.cc @@ -485,6 +485,39 @@ TEST_P(FilterTest, IncompleteRequestWithTrailer) { Http::TestRequestTrailerMapImpl trailers{{"some", "trailer"}}; EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(trailers)); + filter_->decodeComplete(); + + EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.success"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.mismatched_content_type"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.no_body"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.invalid_thrift_body"), 1); +} + +TEST_P(FilterTest, IncompleteRequestWithEarlyComplete) { + const auto [transport_type, protocol_type] = GetParam(); + MessageType message_type = MessageType::Call; + + initializeFilter(config_yaml_); + const std::map& expected_metadata = { + {"protocol", "unknown"}, + {"transport", "unknown"}, + {"request_message_type", "unknown"}, + {"method_name", "unknown"}}; + + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(request_headers_, false)); + EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(stream_info_)); + EXPECT_CALL(stream_info_, setDynamicMetadata("envoy.lb", MapEq(expected_metadata))); + + Buffer::OwnedImpl whole_message; + writeMessage(whole_message, transport_type, protocol_type, message_type); + Buffer::OwnedImpl buffer; + // incomplete message + buffer.move(whole_message, whole_message.length() / 2); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->decodeData(buffer, false)); + + filter_->decodeComplete(); + EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.success"), 0); EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.mismatched_content_type"), 0); EXPECT_EQ(getCounterValue("thrift_to_metadata.rq.no_body"), 0); @@ -518,6 +551,40 @@ TEST_P(FilterTest, IncompleteResponseWithTrailer) { Http::TestResponseTrailerMapImpl trailers{{"some", "trailer"}}; EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(trailers)); + filter_->encodeComplete(); + + EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.success"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.mismatched_content_type"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.no_body"), 0); + EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.invalid_thrift_body"), 1); +} + +TEST_P(FilterTest, IncompleteResponseEarlyComplete) { + const auto [transport_type, protocol_type] = GetParam(); + MessageType message_type = MessageType::Reply; + + initializeFilter(config_yaml_); + const std::map& expected_metadata = { + {"protocol", "unknown"}, + {"transport", "unknown"}, + {"response_message_type", "unknown"}, + {"method_name", "unknown"}, + {"response_reply_type", "unknown"}}; + + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->encodeHeaders(response_headers_, false)); + EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(stream_info_)); + EXPECT_CALL(stream_info_, setDynamicMetadata(HttpFilterNames::get().ThriftToMetadata, + MapEq(expected_metadata))); + + Buffer::OwnedImpl whole_message; + writeMessage(whole_message, transport_type, protocol_type, message_type, ReplyType::Success); + Buffer::OwnedImpl buffer; + // incomplete message + buffer.move(whole_message, whole_message.length() / 2); + EXPECT_EQ(Http::FilterDataStatus::StopIterationAndBuffer, filter_->encodeData(buffer, false)); + + filter_->encodeComplete(); EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.success"), 0); EXPECT_EQ(getCounterValue("thrift_to_metadata.resp.mismatched_content_type"), 0); diff --git a/test/extensions/filters/network/http_connection_manager/config_filter_chain_test.cc b/test/extensions/filters/network/http_connection_manager/config_filter_chain_test.cc index 9cc93b5749b9..29048d827af6 100644 --- a/test/extensions/filters/network/http_connection_manager/config_filter_chain_test.cc +++ b/test/extensions/filters/network/http_connection_manager/config_filter_chain_test.cc @@ -186,15 +186,15 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChain) { ASSERT_TRUE(creation_status_.ok()); NiceMock manager; - Http::EmptyFilterChainOptions option; - ; + const Http::EmptyFilterChainOptions options; + // Check the case where WebSockets are configured in the HCM, and no router // config is present. We should create an upgrade filter chain for // WebSockets. { EXPECT_CALL(manager.callbacks_, addStreamFilter(_)); // Buffer EXPECT_CALL(manager.callbacks_, addStreamDecoderFilter(_)); // Router - EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", nullptr, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", nullptr, manager, options)); } // Check the case where WebSockets are configured in the HCM, and no router @@ -202,7 +202,7 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChain) { { EXPECT_CALL(manager.callbacks_, addStreamFilter(_)).Times(0); EXPECT_CALL(manager.callbacks_, addStreamDecoderFilter(_)).Times(0); - EXPECT_FALSE(config.createUpgradeFilterChain("foo", nullptr, manager, option)); + EXPECT_FALSE(config.createUpgradeFilterChain("foo", nullptr, manager, options)); } // Now override the HCM with a route-specific disabling of WebSocket to @@ -210,7 +210,7 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChain) { { std::map upgrade_map; upgrade_map.emplace(std::make_pair("WebSocket", false)); - EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, option)); + EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, options)); } // For paranoia's sake make sure route-specific enabling doesn't break @@ -220,7 +220,7 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChain) { EXPECT_CALL(manager.callbacks_, addStreamDecoderFilter(_)); // Router std::map upgrade_map; upgrade_map.emplace(std::make_pair("WebSocket", true)); - EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, options)); } } @@ -237,23 +237,23 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChainHCMDisabled) { ASSERT_TRUE(creation_status_.ok()); NiceMock manager; - Http::EmptyFilterChainOptions option; + const Http::EmptyFilterChainOptions options; // Check the case where WebSockets are off in the HCM, and no router config is present. - { EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", nullptr, manager, option)); } + { EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", nullptr, manager, options)); } // Check the case where WebSockets are off in the HCM and in router config. { std::map upgrade_map; upgrade_map.emplace(std::make_pair("WebSocket", false)); - EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, option)); + EXPECT_FALSE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, options)); } // With a route-specific enabling for WebSocket, WebSocket should work. { std::map upgrade_map; upgrade_map.emplace(std::make_pair("WebSocket", true)); - EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("WEBSOCKET", &upgrade_map, manager, options)); } // With only a route-config we should do what the route config says. @@ -261,9 +261,9 @@ TEST_F(FilterChainTest, CreateUpgradeFilterChainHCMDisabled) { std::map upgrade_map; upgrade_map.emplace(std::make_pair("foo", true)); upgrade_map.emplace(std::make_pair("bar", false)); - EXPECT_TRUE(config.createUpgradeFilterChain("foo", &upgrade_map, manager, option)); - EXPECT_FALSE(config.createUpgradeFilterChain("bar", &upgrade_map, manager, option)); - EXPECT_FALSE(config.createUpgradeFilterChain("eep", &upgrade_map, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("foo", &upgrade_map, manager, options)); + EXPECT_FALSE(config.createUpgradeFilterChain("bar", &upgrade_map, manager, options)); + EXPECT_FALSE(config.createUpgradeFilterChain("eep", &upgrade_map, manager, options)); } } @@ -294,7 +294,7 @@ TEST_F(FilterChainTest, CreateCustomUpgradeFilterChain) { filter_config_provider_manager_, creation_status_); ASSERT_TRUE(creation_status_.ok()); - Http::EmptyFilterChainOptions option; + const Http::EmptyFilterChainOptions options; { NiceMock manager; @@ -306,14 +306,14 @@ TEST_F(FilterChainTest, CreateCustomUpgradeFilterChain) { { NiceMock manager; EXPECT_CALL(manager.callbacks_, addStreamDecoderFilter(_)); - EXPECT_TRUE(config.createUpgradeFilterChain("websocket", nullptr, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("websocket", nullptr, manager, options)); } { NiceMock manager; EXPECT_CALL(manager.callbacks_, addStreamDecoderFilter(_)); EXPECT_CALL(manager.callbacks_, addStreamFilter(_)).Times(2); // Buffer - EXPECT_TRUE(config.createUpgradeFilterChain("Foo", nullptr, manager, option)); + EXPECT_TRUE(config.createUpgradeFilterChain("Foo", nullptr, manager, options)); } } diff --git a/test/extensions/filters/network/rbac/filter_test.cc b/test/extensions/filters/network/rbac/filter_test.cc index 9ca7ad06483e..cdc9ed2f6b4e 100644 --- a/test/extensions/filters/network/rbac/filter_test.cc +++ b/test/extensions/filters/network/rbac/filter_test.cc @@ -10,6 +10,7 @@ #include "source/extensions/filters/network/rbac/rbac_filter.h" #include "source/extensions/filters/network/well_known_names.h" +#include "test/mocks/event/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/server/factory_context.h" @@ -29,7 +30,8 @@ class RoleBasedAccessControlNetworkFilterTest : public testing::Test { public: void setupPolicy(bool with_policy = true, bool continuous = false, - envoy::config::rbac::v3::RBAC::Action action = envoy::config::rbac::v3::RBAC::ALLOW) { + envoy::config::rbac::v3::RBAC::Action action = envoy::config::rbac::v3::RBAC::ALLOW, + int64_t delay_deny_duration_ms = 0) { envoy::extensions::filters::network::rbac::v3::RBAC config; config.set_stat_prefix("tcp."); @@ -58,11 +60,14 @@ class RoleBasedAccessControlNetworkFilterTest : public testing::Test { config.set_enforcement_type(envoy::extensions::filters::network::rbac::v3::RBAC::CONTINUOUS); } + if (delay_deny_duration_ms > 0) { + (*config.mutable_delay_deny()) = + ProtobufUtil::TimeUtil::MillisecondsToDuration(delay_deny_duration_ms); + } + config_ = std::make_shared( config, *store_.rootScope(), context_, ProtobufMessage::getStrictValidationVisitor()); - - filter_ = std::make_unique(config_); - filter_->initializeReadFilterCallbacks(callbacks_); + initFilter(); } void setupMatcher(bool with_matcher = true, bool continuous = false, std::string action = "ALLOW", @@ -163,12 +168,10 @@ class RoleBasedAccessControlNetworkFilterTest : public testing::Test { config_ = std::make_shared( config, *store_.rootScope(), context_, ProtobufMessage::getStrictValidationVisitor()); - - filter_ = std::make_unique(config_); - filter_->initializeReadFilterCallbacks(callbacks_); + initFilter(); } - RoleBasedAccessControlNetworkFilterTest() { + void initFilter() { EXPECT_CALL(callbacks_, connection()).WillRepeatedly(ReturnRef(callbacks_.connection_)); EXPECT_CALL(callbacks_.connection_, streamInfo()).WillRepeatedly(ReturnRef(stream_info_)); @@ -347,6 +350,28 @@ TEST_F(RoleBasedAccessControlNetworkFilterTest, Denied) { filter_meta.fields().at("shadow_rules_prefix_shadow_engine_result").string_value()); } +TEST_F(RoleBasedAccessControlNetworkFilterTest, DelayDenied) { + int64_t delay_deny_duration_ms = 500; + setupPolicy(true, false, envoy::config::rbac::v3::RBAC::ALLOW, delay_deny_duration_ms); + setDestinationPort(789); + + // Only call close() once since the connection is delay denied. + EXPECT_CALL(callbacks_.connection_, readDisable(true)); + EXPECT_CALL(callbacks_.connection_, close(Network::ConnectionCloseType::NoFlush, _)); + + Event::MockTimer* delay_timer = + new NiceMock(&callbacks_.connection_.dispatcher_); + EXPECT_CALL(*delay_timer, enableTimer(std::chrono::milliseconds(delay_deny_duration_ms), _)); + + // Call onData() twice, should only increase stats once. + EXPECT_EQ(Network::FilterStatus::StopIteration, filter_->onData(data_, false)); + EXPECT_EQ(Network::FilterStatus::StopIteration, filter_->onData(data_, false)); + EXPECT_EQ(0U, config_->stats().allowed_.value()); + EXPECT_EQ(1U, config_->stats().denied_.value()); + + delay_timer->invokeCallback(); +} + TEST_F(RoleBasedAccessControlNetworkFilterTest, MatcherAllowedWithOneTimeEnforcement) { setupMatcher(); diff --git a/test/extensions/filters/network/rbac/integration_test.cc b/test/extensions/filters/network/rbac/integration_test.cc index f8018eaff5db..c07ce6612552 100644 --- a/test/extensions/filters/network/rbac/integration_test.cc +++ b/test/extensions/filters/network/rbac/integration_test.cc @@ -7,6 +7,7 @@ #include "test/integration/integration.h" #include "test/test_common/environment.h" +#include "test/test_common/simulated_time_system.h" #include "fmt/printf.h" @@ -22,6 +23,7 @@ std::string rbac_config; class RoleBasedAccessControlNetworkFilterIntegrationTest : public testing::TestWithParam, + public Event::TestUsingSimulatedTime, public BaseIntegrationTest { public: RoleBasedAccessControlNetworkFilterIntegrationTest() @@ -133,6 +135,36 @@ name: rbac EXPECT_EQ(0U, test_server_->counter("tcp.rbac.shadow_denied")->value()); } +TEST_P(RoleBasedAccessControlNetworkFilterIntegrationTest, DelayDenied) { + initializeFilter(R"EOF( +name: rbac +typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC + stat_prefix: tcp. + rules: + policies: + "deny_all": + permissions: + - any: true + principals: + - not_id: + any: true + delay_deny: 5s +)EOF"); + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); + ASSERT_TRUE(tcp_client->write("hello", false, false)); + ASSERT_TRUE(tcp_client->connected()); + + timeSystem().advanceTimeWait(std::chrono::seconds(3)); + ASSERT_TRUE(tcp_client->connected()); + + timeSystem().advanceTimeWait(std::chrono::seconds(6)); + tcp_client->waitForDisconnect(); + + EXPECT_EQ(0U, test_server_->counter("tcp.rbac.allowed")->value()); + EXPECT_EQ(1U, test_server_->counter("tcp.rbac.denied")->value()); +} + TEST_P(RoleBasedAccessControlNetworkFilterIntegrationTest, DeniedWithDenyAction) { useListenerAccessLog("%CONNECTION_TERMINATION_DETAILS%"); initializeFilter(R"EOF( diff --git a/test/extensions/filters/udp/udp_proxy/BUILD b/test/extensions/filters/udp/udp_proxy/BUILD index 1e28d7588b80..e785b5ca694c 100644 --- a/test/extensions/filters/udp/udp_proxy/BUILD +++ b/test/extensions/filters/udp/udp_proxy/BUILD @@ -19,7 +19,6 @@ envoy_extension_cc_mock( extension_names = ["envoy.filters.udp_listener.udp_proxy"], deps = [ "//source/extensions/filters/udp/udp_proxy:udp_proxy_filter_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "//test/mocks/network:network_mocks", "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/upstream:upstream_mocks", @@ -95,8 +94,6 @@ envoy_extension_cc_test( "//envoy/network:filter_interface", "//envoy/server:filter_config_interface", "//source/extensions/filters/udp/udp_proxy:config", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_config_interface", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "//test/extensions/filters/udp/udp_proxy/session_filters:buffer_filter_config_lib", "//test/extensions/filters/udp/udp_proxy/session_filters:buffer_filter_proto_cc_proto", "//test/extensions/filters/udp/udp_proxy/session_filters:drainer_filter_config_lib", diff --git a/test/extensions/filters/udp/udp_proxy/mocks.h b/test/extensions/filters/udp/udp_proxy/mocks.h index 7a542e0d7583..fc9135e99b90 100644 --- a/test/extensions/filters/udp/udp_proxy/mocks.h +++ b/test/extensions/filters/udp/udp_proxy/mocks.h @@ -1,6 +1,5 @@ #pragma once -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" #include "source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h" #include "test/mocks/stream_info/mocks.h" @@ -15,7 +14,7 @@ namespace UdpFilters { namespace UdpProxy { namespace SessionFilters { -class MockReadFilterCallbacks : public ReadFilterCallbacks { +class MockReadFilterCallbacks : public Network::UdpSessionReadFilterCallbacks { public: MockReadFilterCallbacks(); ~MockReadFilterCallbacks() override; @@ -29,7 +28,7 @@ class MockReadFilterCallbacks : public ReadFilterCallbacks { NiceMock stream_info_; }; -class MockWriteFilterCallbacks : public WriteFilterCallbacks { +class MockWriteFilterCallbacks : public Network::UdpSessionWriteFilterCallbacks { public: MockWriteFilterCallbacks(); ~MockWriteFilterCallbacks() override; diff --git a/test/extensions/filters/udp/udp_proxy/session_filters/BUILD b/test/extensions/filters/udp/udp_proxy/session_filters/BUILD index 2f20a55c2617..5163923af52f 100644 --- a/test/extensions/filters/udp/udp_proxy/session_filters/BUILD +++ b/test/extensions/filters/udp/udp_proxy/session_filters/BUILD @@ -36,7 +36,6 @@ envoy_cc_test_library( "//envoy/registry", "//source/common/router:string_accessor_lib", "//source/extensions/filters/udp/udp_proxy/session_filters:factory_base_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "//test/test_common:utility_lib", ], alwayslink = 1, @@ -55,7 +54,6 @@ envoy_cc_test_library( "//envoy/registry", "//source/common/router:string_accessor_lib", "//source/extensions/filters/udp/udp_proxy/session_filters:factory_base_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "//test/test_common:utility_lib", ], alwayslink = 1, diff --git a/test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.h b/test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.h index 8f32cb16b51c..56503da0aaf5 100644 --- a/test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.h +++ b/test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.h @@ -7,7 +7,6 @@ #include "source/common/config/utility.h" #include "source/common/router/string_accessor_impl.h" #include "source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.pb.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/buffer_filter.pb.validate.h" @@ -19,6 +18,12 @@ namespace UdpFilters { namespace UdpProxy { namespace SessionFilters { +using Filter = Network::UdpSessionFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using WriteFilterStatus = Network::UdpSessionWriteFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; +using WriteFilterCallbacks = Network::UdpSessionWriteFilterCallbacks; + using BufferingFilterConfig = test::extensions::filters::udp::udp_proxy::session_filters::BufferingFilterConfig; @@ -128,7 +133,7 @@ class BufferingSessionFilterConfigFactory : public FactoryBase void { + return [config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addFilter(std::make_shared( config.downstream_datagrams_to_buffer(), config.upstream_datagrams_to_buffer(), config.continue_after_inject())); diff --git a/test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.h b/test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.h index e9a86a461ac3..a8d7cffbcb22 100644 --- a/test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.h +++ b/test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.h @@ -5,7 +5,6 @@ #include "source/common/config/utility.h" #include "source/common/router/string_accessor_impl.h" #include "source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.pb.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/drainer_filter.pb.validate.h" @@ -24,6 +23,14 @@ using WriteDrainerConfig = using DrainerConfig = test::extensions::filters::udp::udp_proxy::session_filters::DrainerUdpSessionFilterConfig; +using Filter = Network::UdpSessionFilter; +using ReadFilter = Network::UdpSessionReadFilter; +using WriteFilter = Network::UdpSessionWriteFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using WriteFilterStatus = Network::UdpSessionWriteFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; +using WriteFilterCallbacks = Network::UdpSessionWriteFilterCallbacks; + class DrainerUdpSessionReadFilter : public virtual ReadFilter { public: DrainerUdpSessionReadFilter(int downstream_bytes_to_drain, bool stop_iteration_on_new_session, @@ -92,7 +99,7 @@ class DrainerUdpSessionReadFilterConfigFactory : public FactoryBase void { + return [config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addReadFilter(std::make_unique( config.downstream_bytes_to_drain(), config.stop_iteration_on_new_session(), config.stop_iteration_on_first_read(), config.continue_filter_chain())); @@ -135,10 +142,10 @@ class DrainerUdpSessionWriteFilterConfigFactory : public FactoryBase void { + return [config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addWriteFilter(std::make_unique( config.upstream_bytes_to_drain(), config.stop_iteration_on_first_write())); }; @@ -166,10 +173,10 @@ class DrainerUdpSessionFilterConfigFactory : public FactoryBase { DrainerUdpSessionFilterConfigFactory() : FactoryBase("test.udp_session.drainer") {} private: - FilterFactoryCb + Network::UdpSessionFilterFactoryCb createFilterFactoryFromProtoTyped(const DrainerConfig& config, Server::Configuration::FactoryContext&) override { - return [config](FilterChainFactoryCallbacks& callbacks) -> void { + return [config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addFilter(std::make_shared( config.downstream_bytes_to_drain(), config.upstream_bytes_to_drain(), config.stop_iteration_on_new_session(), config.stop_iteration_on_first_read(), diff --git a/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD b/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD index d1a7fada9d12..de0aceff4488 100644 --- a/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD +++ b/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/BUILD @@ -26,8 +26,6 @@ envoy_cc_test_library( "//envoy/registry", "//source/common/router:string_accessor_lib", "//source/common/stream_info:uint32_accessor_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:factory_base_lib", - "//source/extensions/filters/udp/udp_proxy/session_filters:filter_interface", "//test/test_common:utility_lib", ], alwayslink = 1, diff --git a/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.h b/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.h index 28d0e78bb155..c2a39c4d33c6 100644 --- a/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.h +++ b/test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.h @@ -6,7 +6,6 @@ #include "source/common/router/string_accessor_impl.h" #include "source/common/stream_info/uint32_accessor_impl.h" #include "source/extensions/filters/udp/udp_proxy/session_filters/factory_base.h" -#include "source/extensions/filters/udp/udp_proxy/session_filters/filter.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.pb.h" #include "test/extensions/filters/udp/udp_proxy/session_filters/dynamic_forward_proxy/dfp_setter.pb.validate.h" @@ -22,6 +21,10 @@ namespace DynamicForwardProxy { using DynamicForwardProxySetterFilterConfig = test::extensions::filters::udp::udp_proxy:: session_filters::DynamicForwardProxySetterFilterConfig; +using ReadFilter = Network::UdpSessionReadFilter; +using ReadFilterStatus = Network::UdpSessionReadFilterStatus; +using ReadFilterCallbacks = Network::UdpSessionReadFilterCallbacks; + class DynamicForwardProxySetterFilter : public virtual ReadFilter { public: DynamicForwardProxySetterFilter(const std::string host, uint32_t port) @@ -58,7 +61,7 @@ class DynamicForwardProxySetterFilterConfigFactory FilterFactoryCb createFilterFactoryFromProtoTyped(const DynamicForwardProxySetterFilterConfig& config, Server::Configuration::FactoryContext&) override { - return [config](FilterChainFactoryCallbacks& callbacks) -> void { + return [config](Network::UdpSessionFilterChainFactoryCallbacks& callbacks) -> void { callbacks.addReadFilter( std::make_unique(config.host(), config.port())); }; diff --git a/test/extensions/filters/udp/udp_proxy/udp_proxy_filter_test.cc b/test/extensions/filters/udp/udp_proxy/udp_proxy_filter_test.cc index d219f425da4a..51490fa491a7 100644 --- a/test/extensions/filters/udp/udp_proxy/udp_proxy_filter_test.cc +++ b/test/extensions/filters/udp/udp_proxy/udp_proxy_filter_test.cc @@ -1618,6 +1618,10 @@ stat_prefix: foo EXPECT_THAT(output_.front(), testing::HasSubstr("session_complete")); } +using MockUdpTunnelingConfig = SessionFilters::MockUdpTunnelingConfig; +using MockUpstreamTunnelCallbacks = SessionFilters::MockUpstreamTunnelCallbacks; +using MockTunnelCreationCallbacks = SessionFilters::MockTunnelCreationCallbacks; + class HttpUpstreamImplTest : public testing::Test { public: struct HeaderToAdd { @@ -1942,6 +1946,8 @@ TEST_F(HttpUpstreamImplTest, TargetHostPercentEncoding) { setAndExpectRequestEncoder(expected_headers, is_ssl); } +using MockHttpStreamCallbacks = SessionFilters::MockHttpStreamCallbacks; + class TunnelingConnectionPoolImplTest : public testing::Test { public: void setup() { diff --git a/test/extensions/load_balancing_policies/least_request/config_test.cc b/test/extensions/load_balancing_policies/least_request/config_test.cc index 078eb4320a23..d249952aeadc 100644 --- a/test/extensions/load_balancing_policies/least_request/config_test.cc +++ b/test/extensions/load_balancing_policies/least_request/config_test.cc @@ -19,6 +19,7 @@ TEST(LeastRequestConfigTest, ValidateFail) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; envoy::config::core::v3::TypedExtensionConfig config; config.set_name("envoy.load_balancing_policies.least_request"); @@ -28,8 +29,8 @@ TEST(LeastRequestConfigTest, ValidateFail) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.least_request", factory.name()); - auto lb_config = - factory.loadConfig(*factory.createEmptyConfigProto(), context.messageValidationVisitor()); + auto lb_config = factory.loadConfig(lb_factory_context, *factory.createEmptyConfigProto(), + context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, context.api_.random_, context.time_system_); diff --git a/test/extensions/load_balancing_policies/maglev/config_test.cc b/test/extensions/load_balancing_policies/maglev/config_test.cc index 4a35ed7f2c46..d061592ad62f 100644 --- a/test/extensions/load_balancing_policies/maglev/config_test.cc +++ b/test/extensions/load_balancing_policies/maglev/config_test.cc @@ -20,6 +20,7 @@ TEST(MaglevConfigTest, Validate) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; { envoy::config::core::v3::TypedExtensionConfig config; @@ -30,8 +31,8 @@ TEST(MaglevConfigTest, Validate) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.maglev", factory.name()); - auto lb_config = - factory.loadConfig(*factory.createEmptyConfigProto(), context.messageValidationVisitor()); + auto lb_config = factory.loadConfig(lb_factory_context, *factory.createEmptyConfigProto(), + context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, context.api_.random_, context.time_system_); @@ -59,7 +60,8 @@ TEST(MaglevConfigTest, Validate) { auto message_ptr = factory.createEmptyConfigProto(); message_ptr->MergeFrom(config_msg); - auto lb_config = factory.loadConfig(*message_ptr, context.messageValidationVisitor()); + auto lb_config = + factory.loadConfig(lb_factory_context, *message_ptr, context.messageValidationVisitor()); EXPECT_THROW_WITH_MESSAGE(factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, context.api_.random_, diff --git a/test/extensions/load_balancing_policies/random/config_test.cc b/test/extensions/load_balancing_policies/random/config_test.cc index ceba884544c4..b3d30eb9871a 100644 --- a/test/extensions/load_balancing_policies/random/config_test.cc +++ b/test/extensions/load_balancing_policies/random/config_test.cc @@ -19,6 +19,7 @@ TEST(RandomConfigTest, ValidateFail) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; envoy::config::core::v3::TypedExtensionConfig config; config.set_name("envoy.load_balancing_policies.random"); @@ -28,8 +29,8 @@ TEST(RandomConfigTest, ValidateFail) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.random", factory.name()); - auto lb_config = - factory.loadConfig(*factory.createEmptyConfigProto(), context.messageValidationVisitor()); + auto lb_config = factory.loadConfig(lb_factory_context, *factory.createEmptyConfigProto(), + context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, context.api_.random_, context.time_system_); diff --git a/test/extensions/load_balancing_policies/ring_hash/config_test.cc b/test/extensions/load_balancing_policies/ring_hash/config_test.cc index f94ffc01649f..c978ca41872c 100644 --- a/test/extensions/load_balancing_policies/ring_hash/config_test.cc +++ b/test/extensions/load_balancing_policies/ring_hash/config_test.cc @@ -21,6 +21,7 @@ TEST(RingHashConfigTest, Validate) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; { envoy::config::core::v3::TypedExtensionConfig config; @@ -31,8 +32,8 @@ TEST(RingHashConfigTest, Validate) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.ring_hash", factory.name()); - auto lb_config = - factory.loadConfig(*factory.createEmptyConfigProto(), context.messageValidationVisitor()); + auto lb_config = factory.loadConfig(lb_factory_context, *factory.createEmptyConfigProto(), + context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, context.api_.random_, context.time_system_); @@ -64,7 +65,8 @@ TEST(RingHashConfigTest, Validate) { auto message_ptr = factory.createEmptyConfigProto(); message_ptr->MergeFrom(config_msg); - auto lb_config = factory.loadConfig(*message_ptr, context.messageValidationVisitor()); + auto lb_config = + factory.loadConfig(lb_factory_context, *message_ptr, context.messageValidationVisitor()); EXPECT_THROW_WITH_MESSAGE( factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, diff --git a/test/extensions/load_balancing_policies/round_robin/config_test.cc b/test/extensions/load_balancing_policies/round_robin/config_test.cc index 81a51c2b45ed..d845c71168c2 100644 --- a/test/extensions/load_balancing_policies/round_robin/config_test.cc +++ b/test/extensions/load_balancing_policies/round_robin/config_test.cc @@ -19,6 +19,7 @@ TEST(RoundRobinConfigTest, ValidateFail) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; envoy::config::core::v3::TypedExtensionConfig config; config.set_name("envoy.load_balancing_policies.round_robin"); @@ -28,8 +29,8 @@ TEST(RoundRobinConfigTest, ValidateFail) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.round_robin", factory.name()); - auto lb_config = - factory.loadConfig(*factory.createEmptyConfigProto(), context.messageValidationVisitor()); + auto lb_config = factory.loadConfig(lb_factory_context, *factory.createEmptyConfigProto(), + context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, diff --git a/test/extensions/load_balancing_policies/subset/BUILD b/test/extensions/load_balancing_policies/subset/BUILD index a56bdcdbf460..689deaaf9d21 100644 --- a/test/extensions/load_balancing_policies/subset/BUILD +++ b/test/extensions/load_balancing_policies/subset/BUILD @@ -88,6 +88,7 @@ envoy_extension_cc_benchmark_binary( "//source/extensions/load_balancing_policies/random:config", "//source/extensions/load_balancing_policies/subset:config", "//test/extensions/load_balancing_policies/common:benchmark_base_tester_lib", + "//test/mocks/upstream:load_balancer_mocks", "@envoy_api//envoy/config/cluster/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/load_balancing_policies/random/v3:pkg_cc_proto", "@envoy_api//envoy/extensions/load_balancing_policies/subset/v3:pkg_cc_proto", diff --git a/test/extensions/load_balancing_policies/subset/config_test.cc b/test/extensions/load_balancing_policies/subset/config_test.cc index fa021bc962fc..ef9662a06b57 100644 --- a/test/extensions/load_balancing_policies/subset/config_test.cc +++ b/test/extensions/load_balancing_policies/subset/config_test.cc @@ -20,6 +20,7 @@ TEST(SubsetConfigTest, SubsetConfigTest) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; envoy::config::core::v3::TypedExtensionConfig config; config.set_name("envoy.load_balancing_policies.subset"); @@ -50,7 +51,8 @@ TEST(SubsetConfigTest, SubsetConfigTest) { auto& factory = Config::Utility::getAndCheckFactory(config); EXPECT_EQ("envoy.load_balancing_policies.subset", factory.name()); - auto lb_config = factory.loadConfig(*config_msg, context.messageValidationVisitor()); + auto lb_config = + factory.loadConfig(lb_factory_context, *config_msg, context.messageValidationVisitor()); auto thread_aware_lb = factory.create(*lb_config, cluster_info, main_thread_priority_set, context.runtime_loader_, @@ -71,6 +73,7 @@ TEST(SubsetConfigTest, SubsetConfigTestWithUnknownSubsetLoadBalancingPolicy) { NiceMock cluster_info; NiceMock main_thread_priority_set; NiceMock thread_local_priority_set; + NiceMock lb_factory_context; envoy::config::core::v3::TypedExtensionConfig config; config.set_name("envoy.load_balancing_policies.subset"); @@ -100,7 +103,8 @@ TEST(SubsetConfigTest, SubsetConfigTestWithUnknownSubsetLoadBalancingPolicy) { EXPECT_EQ("envoy.load_balancing_policies.subset", factory.name()); EXPECT_THROW_WITH_MESSAGE( - factory.loadConfig(*config_msg, context.messageValidationVisitor()), EnvoyException, + factory.loadConfig(lb_factory_context, *config_msg, context.messageValidationVisitor()), + EnvoyException, "cluster: didn't find a registered load balancer factory implementation for subset lb with " "names from [envoy.load_balancing_policies.unknown]"); } diff --git a/test/extensions/load_balancing_policies/subset/subset_benchmark.cc b/test/extensions/load_balancing_policies/subset/subset_benchmark.cc index eaeaec500268..1d2d01281c12 100644 --- a/test/extensions/load_balancing_policies/subset/subset_benchmark.cc +++ b/test/extensions/load_balancing_policies/subset/subset_benchmark.cc @@ -16,6 +16,7 @@ #include "test/common/upstream/utility.h" #include "test/extensions/load_balancing_policies/common/benchmark_base_tester.h" #include "test/mocks/upstream/cluster_info.h" +#include "test/mocks/upstream/load_balancer.h" #include "test/test_common/simulated_time_system.h" #include "absl/types/optional.h" @@ -42,9 +43,10 @@ class SubsetLbTester : public Upstream::BaseTester { child_lb->mutable_typed_extension_config()->set_name("envoy.load_balancing_policies.random"); envoy::extensions::load_balancing_policies::random::v3::Random random_lb_config; child_lb->mutable_typed_extension_config()->mutable_typed_config()->PackFrom(random_lb_config); + NiceMock lb_factory_context; subset_config_ = std::make_unique( - subset_config_proto, ProtobufMessage::getStrictValidationVisitor()); + lb_factory_context, subset_config_proto, ProtobufMessage::getStrictValidationVisitor()); lb_ = std::make_unique(*subset_config_, *info_, priority_set_, &local_priority_set_, stats_, stats_scope_, diff --git a/test/extensions/load_balancing_policies/subset/subset_test.cc b/test/extensions/load_balancing_policies/subset/subset_test.cc index adf9b6d01b98..5788ad5e7d44 100644 --- a/test/extensions/load_balancing_policies/subset/subset_test.cc +++ b/test/extensions/load_balancing_policies/subset/subset_test.cc @@ -705,6 +705,7 @@ class SubsetLoadBalancerTest : public Event::TestUsingSimulatedTime, } std::string child_lb_name_{"envoy.load_balancing_policies.round_robin"}; + NiceMock lb_factory_context_; LoadBalancerConfigPtr child_lb_config_; NiceMock priority_set_; MockHostSet& host_set_ = *priority_set_.getMockHostSet(0); @@ -2332,8 +2333,8 @@ TEST_F(SubsetLoadBalancerTest, EnabledLocalityWeightAwareness) { Config::Utility::getFactoryByName(child_lb_name_); envoy::extensions::load_balancing_policies::round_robin::v3::RoundRobin rr_config; rr_config.mutable_locality_lb_config()->mutable_locality_weighted_lb_config(); - child_lb_config_ = - child_factory->loadConfig(rr_config, ProtobufMessage::getStrictValidationVisitor()); + child_lb_config_ = child_factory->loadConfig(lb_factory_context_, rr_config, + ProtobufMessage::getStrictValidationVisitor()); initLbConfigAndLB(); TestLoadBalancerContext context({{"version", "1.1"}}); @@ -2371,8 +2372,8 @@ TEST_F(SubsetLoadBalancerTest, EnabledScaleLocalityWeights) { Config::Utility::getFactoryByName(child_lb_name_); envoy::extensions::load_balancing_policies::round_robin::v3::RoundRobin rr_config; rr_config.mutable_locality_lb_config()->mutable_locality_weighted_lb_config(); - child_lb_config_ = - child_factory->loadConfig(rr_config, ProtobufMessage::getStrictValidationVisitor()); + child_lb_config_ = child_factory->loadConfig(lb_factory_context_, rr_config, + ProtobufMessage::getStrictValidationVisitor()); initLbConfigAndLB(); TestLoadBalancerContext context({{"version", "1.1"}}); @@ -2421,8 +2422,8 @@ TEST_F(SubsetLoadBalancerTest, EnabledScaleLocalityWeightsRounding) { Config::Utility::getFactoryByName(child_lb_name_); envoy::extensions::load_balancing_policies::round_robin::v3::RoundRobin rr_config; rr_config.mutable_locality_lb_config()->mutable_locality_weighted_lb_config(); - child_lb_config_ = - child_factory->loadConfig(rr_config, ProtobufMessage::getStrictValidationVisitor()); + child_lb_config_ = child_factory->loadConfig(lb_factory_context_, rr_config, + ProtobufMessage::getStrictValidationVisitor()); initLbConfigAndLB(); TestLoadBalancerContext context({{"version", "1.0"}}); diff --git a/test/extensions/matching/input_matchers/metadata/BUILD b/test/extensions/matching/input_matchers/metadata/BUILD new file mode 100644 index 000000000000..e77588a746a2 --- /dev/null +++ b/test/extensions/matching/input_matchers/metadata/BUILD @@ -0,0 +1,33 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "dyn_meta_matcher_test", + srcs = ["dyn_meta_matcher_test.cc"], + extension_names = ["envoy.matching.matchers.metadata_matcher"], + deps = [ + "//source/common/matcher:matcher_lib", + "//source/extensions/matching/http/metadata_input:metadata_input_lib", + "//source/extensions/matching/input_matchers/metadata:config", + "//source/extensions/matching/input_matchers/metadata:metadata_lib", + "//test/common/matcher:test_utility_lib", + "//test/mocks/http:http_mocks", + "//test/mocks/matcher:matcher_mocks", + "//test/mocks/server:factory_context_mocks", + "//test/mocks/stream_info:stream_info_mocks", + "//test/test_common:registry_lib", + "@com_github_cncf_xds//xds/type/matcher/v3:pkg_cc_proto", + "@envoy_api//envoy/config/common/matcher/v3:pkg_cc_proto", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/matching/input_matchers/metadata/dyn_meta_matcher_test.cc b/test/extensions/matching/input_matchers/metadata/dyn_meta_matcher_test.cc new file mode 100644 index 000000000000..58df2f51e16b --- /dev/null +++ b/test/extensions/matching/input_matchers/metadata/dyn_meta_matcher_test.cc @@ -0,0 +1,162 @@ +#include +#include + +#include "envoy/config/common/matcher/v3/matcher.pb.validate.h" +#include "envoy/config/core/v3/extension.pb.h" +#include "envoy/matcher/matcher.h" +#include "envoy/registry/registry.h" + +#include "source/common/matcher/matcher.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/matching/http/metadata_input/meta_input.h" +#include "source/extensions/matching/input_matchers/metadata/config.h" +#include "source/extensions/matching/input_matchers/metadata/matcher.h" + +#include "test/common/matcher/test_utility.h" +#include "test/mocks/matcher/mocks.h" +#include "test/mocks/server/factory_context.h" +#include "test/test_common/registry.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" +#include "xds/type/matcher/v3/matcher.pb.validate.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace InputMatchers { +namespace Metadata { + +constexpr absl::string_view kFilterNamespace = "meta_matcher"; +constexpr absl::string_view kMetadataKey = "service_name"; +constexpr absl::string_view kMetadataValue = "test_service"; + +class MetadataMatcherTest : public ::testing::Test { +public: + MetadataMatcherTest() + : inject_action_(action_factory_), + data_(Envoy::Http::Matching::HttpMatchingDataImpl(stream_info_)) {} + + ::Envoy::Matcher::MatchTreeSharedPtr + buildMatcherTree(bool invert = false) { + envoy::extensions::matching::input_matchers::metadata::v3::Metadata meta_matcher; + meta_matcher.mutable_value()->mutable_string_match()->set_exact(kMetadataValue); + meta_matcher.set_invert(invert); + + xds::type::matcher::v3::Matcher matcher; + auto* inner_matcher = matcher.mutable_matcher_list()->add_matchers(); + auto* single_predicate = inner_matcher->mutable_predicate()->mutable_single_predicate(); + + envoy::extensions::matching::common_inputs::network::v3::DynamicMetadataInput metadata_input; + metadata_input.set_filter(kFilterNamespace); + metadata_input.mutable_path()->Add()->set_key(kMetadataKey); + single_predicate->mutable_input()->set_name("envoy.matching.inputs.dynamic_metadata"); + single_predicate->mutable_input()->mutable_typed_config()->PackFrom(metadata_input); + + auto* custom_matcher = single_predicate->mutable_custom_match(); + custom_matcher->mutable_typed_config()->PackFrom(meta_matcher); + + xds::type::matcher::v3::Matcher::OnMatch on_match; + std::string on_match_config = R"EOF( + action: + name: test_action + typed_config: + "@type": type.googleapis.com/google.protobuf.StringValue + value: match!! + )EOF"; + MessageUtil::loadFromYaml(on_match_config, on_match, + ProtobufMessage::getStrictValidationVisitor()); + + inner_matcher->mutable_on_match()->MergeFrom(on_match); + + auto string_factory_on_match = ::Envoy::Matcher::TestDataInputStringFactory("value"); + + ::Envoy::Matcher::MockMatchTreeValidationVisitor + validation_visitor; + EXPECT_CALL(validation_visitor, + performDataInputValidation( + _, "type.googleapis.com/" + "envoy.extensions.matching.common_inputs.network.v3.DynamicMetadataInput")); + ::Envoy::Matcher::MatchTreeFactory + matcher_factory(context_, factory_context_, validation_visitor); + auto match_tree = matcher_factory.create(matcher); + + return match_tree(); + } + + void setDynamicMetadata(const std::string& namespace_str, const std::string& metadata_key, + const std::string& metadata_value) { + Envoy::Config::Metadata::mutableMetadataValue(stream_info_.metadata_, namespace_str, + metadata_key) + .set_string_value(metadata_value); + } + + ::Envoy::Matcher::StringActionFactory action_factory_; + Registry::InjectFactory> inject_action_; + testing::NiceMock stream_info_; + absl::string_view context_ = ""; + testing::NiceMock factory_context_; + envoy::config::core::v3::Metadata metadata_; + + Envoy::Http::Matching::HttpMatchingDataImpl data_; +}; + +TEST_F(MetadataMatcherTest, DynamicMetadataMatched) { + setDynamicMetadata(std::string(kFilterNamespace), std::string(kMetadataKey), + std::string(kMetadataValue)); + Envoy::Http::Matching::HttpMatchingDataImpl data = + Envoy::Http::Matching::HttpMatchingDataImpl(stream_info_); + auto matcher_tree = buildMatcherTree(); + const auto result = matcher_tree->match(data_); + // The match was complete, match found. + EXPECT_EQ(result.match_state_, ::Envoy::Matcher::MatchState::MatchComplete); + EXPECT_TRUE(result.on_match_.has_value()); + EXPECT_NE(result.on_match_->action_cb_, nullptr); +} + +TEST_F(MetadataMatcherTest, DynamicMetadataNotMatched) { + setDynamicMetadata(std::string(kFilterNamespace), std::string(kMetadataKey), "wrong_service"); + Envoy::Http::Matching::HttpMatchingDataImpl data = + Envoy::Http::Matching::HttpMatchingDataImpl(stream_info_); + auto matcher_tree = buildMatcherTree(); + + const auto result = matcher_tree->match(data_); + // The match was completed, no match found. + EXPECT_EQ(result.match_state_, ::Envoy::Matcher::MatchState::MatchComplete); + EXPECT_EQ(result.on_match_, absl::nullopt); +} + +TEST_F(MetadataMatcherTest, DynamicMetadataNotMatchedWithInvert) { + setDynamicMetadata(std::string(kFilterNamespace), std::string(kMetadataKey), "wrong_service"); + Envoy::Http::Matching::HttpMatchingDataImpl data = + Envoy::Http::Matching::HttpMatchingDataImpl(stream_info_); + auto matcher_tree = buildMatcherTree(true); + + const auto result = matcher_tree->match(data_); + // The match was completed, no match found but the invert flag was set. + EXPECT_EQ(result.match_state_, ::Envoy::Matcher::MatchState::MatchComplete); + EXPECT_TRUE(result.on_match_.has_value()); + EXPECT_NE(result.on_match_->action_cb_, nullptr); +} + +TEST_F(MetadataMatcherTest, BadData) { + envoy::extensions::matching::input_matchers::metadata::v3::Metadata meta_matcher; + meta_matcher.mutable_value()->mutable_string_match()->set_exact(kMetadataValue); + const auto& matcher_config = MessageUtil::downcastAndValidate< + const envoy::extensions::matching::input_matchers::metadata::v3::Metadata&>( + meta_matcher, factory_context_.messageValidationVisitor()); + const auto& v = matcher_config.value(); + auto value_matcher = Envoy::Matchers::ValueMatcher::create(v, factory_context_); + + ::Envoy::Matcher::MatchingDataType data = absl::monostate(); + EXPECT_NO_THROW(Matcher(value_matcher, false).match(data)); + + ::Envoy::Matcher::MatchingDataType data2 = std::string("test"); + EXPECT_NO_THROW(Matcher(value_matcher, false).match(data2)); +} + +} // namespace Metadata +} // namespace InputMatchers +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/network/dns_resolver/apple/apple_dns_impl_test.cc b/test/extensions/network/dns_resolver/apple/apple_dns_impl_test.cc index a1b86871da1d..ae263ae91fcf 100644 --- a/test/extensions/network/dns_resolver/apple/apple_dns_impl_test.cc +++ b/test/extensions/network/dns_resolver/apple/apple_dns_impl_test.cc @@ -672,8 +672,8 @@ class AppleDnsImplFakeApiTest : public testing::Test { EXPECT_NE(nullptr, response.front().addrInfo().address_->ip()->ipv6()); break; case AddressType::Both: - EXPECT_NE(nullptr, response.front().addrInfo().address_->ip()->ipv4()); - EXPECT_NE(nullptr, response.back().addrInfo().address_->ip()->ipv6()); + EXPECT_NE(nullptr, response.back().addrInfo().address_->ip()->ipv4()); + EXPECT_NE(nullptr, response.front().addrInfo().address_->ip()->ipv6()); break; default: PANIC("reached unexpected code"); diff --git a/test/extensions/network/dns_resolver/cares/dns_impl_test.cc b/test/extensions/network/dns_resolver/cares/dns_impl_test.cc index 6bd911aa7667..b57c5e4a80c8 100644 --- a/test/extensions/network/dns_resolver/cares/dns_impl_test.cc +++ b/test/extensions/network/dns_resolver/cares/dns_impl_test.cc @@ -72,10 +72,10 @@ class TestDnsServerQuery { TestDnsServerQuery(ConnectionPtr connection, const HostMap& hosts_a, const HostMap& hosts_aaaa, const CNameMap& cnames, const std::chrono::seconds& record_ttl, const std::chrono::seconds& cname_ttl_, bool refused, bool error_on_a, - bool error_on_aaaa) + bool error_on_aaaa, bool no_response) : connection_(std::move(connection)), hosts_a_(hosts_a), hosts_aaaa_(hosts_aaaa), cnames_(cnames), record_ttl_(record_ttl), cname_ttl_(cname_ttl_), refused_(refused), - error_on_a_(error_on_a), error_on_aaaa_(error_on_aaaa) { + error_on_a_(error_on_a), error_on_aaaa_(error_on_aaaa), no_response_(no_response) { connection_->addReadFilter(Network::ReadFilterSharedPtr{new ReadFilter(*this)}); } @@ -164,7 +164,9 @@ class TestDnsServerQuery { const auto addrs = getAddrs(q_type, lookup_name); auto buf = createAddrResolutionBuffer(q_type, addrs, request, name_len, encoded_cname, encoded_name); - parent_.connection_->write(buf, false); + if (!parent_.no_response_) { + parent_.connection_->write(buf, false); + } // Reset query state, time for the next one. buffer_.drain(size_); @@ -335,21 +337,23 @@ class TestDnsServerQuery { const bool refused_; const bool error_on_a_; const bool error_on_aaaa_; + const bool no_response_{false}; }; class TestDnsServer : public TcpListenerCallbacks { public: - TestDnsServer(Event::Dispatcher& dispatcher) + TestDnsServer(Event::Dispatcher& dispatcher, bool no_response) : dispatcher_(dispatcher), record_ttl_(0), cname_ttl_(0), stream_info_(dispatcher.timeSource(), nullptr, - StreamInfo::FilterState::LifeSpan::Connection) {} + StreamInfo::FilterState::LifeSpan::Connection), + no_response_(no_response) {} void onAccept(ConnectionSocketPtr&& socket) override { Network::ConnectionPtr new_connection = dispatcher_.createServerConnection( std::move(socket), Network::Test::createRawBufferSocket(), stream_info_); - TestDnsServerQuery* query = - new TestDnsServerQuery(std::move(new_connection), hosts_a_, hosts_aaaa_, cnames_, - record_ttl_, cname_ttl_, refused_, error_on_a_, error_on_aaaa_); + TestDnsServerQuery* query = new TestDnsServerQuery( + std::move(new_connection), hosts_a_, hosts_aaaa_, cnames_, record_ttl_, cname_ttl_, + refused_, error_on_a_, error_on_aaaa_, no_response_); queries_.emplace_back(query); } @@ -389,6 +393,7 @@ class TestDnsServer : public TcpListenerCallbacks { // over. std::vector> queries_; StreamInfo::StreamInfoImpl stream_info_; + const bool no_response_{false}; }; } // namespace @@ -730,7 +735,7 @@ class DnsImplTest : public testing::TestWithParam { void SetUp() override { // Instantiate TestDnsServer and listen on a random port on the loopback address. - server_ = std::make_unique(*dispatcher_); + server_ = std::make_unique(*dispatcher_, queryTimeout()); socket_ = std::make_shared( Network::Test::getCanonicalLoopbackAddress(GetParam())); NiceMock listener_config; @@ -763,7 +768,7 @@ class DnsImplTest : public testing::TestWithParam { void resetChannel() { if (tcpOnly()) { - peer_->resetChannelTcpOnly(zeroTimeout()); + peer_->resetChannelTcpOnly(queryTimeout()); } ares_set_servers_ports_csv( peer_->channel(), socket_->connectionInfoProvider().localAddress()->asString().c_str()); @@ -951,8 +956,8 @@ class DnsImplTest : public testing::TestWithParam { } protected: - // Should the DnsResolverImpl use a zero timeout for c-ares queries? - virtual bool zeroTimeout() const { return false; } + // Should the TestDnsServer cause c-ares queries to timeout, by not responding? + virtual bool queryTimeout() const { return false; } virtual bool tcpOnly() const { return true; } virtual void updateDnsResolverOptions(){}; virtual bool setResolverInConstructor() const { return false; } @@ -980,7 +985,8 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, DnsImplTest, // development, where segfaults were encountered due to callback invocations on // destruction. TEST_P(DnsImplTest, DestructPending) { - ActiveDnsQuery* query = resolveWithUnreferencedParameters("", DnsLookupFamily::V4Only, false); + ActiveDnsQuery* query = + resolveWithUnreferencedParameters("foo.bar.baz", DnsLookupFamily::V4Only, false); ASSERT_NE(nullptr, query); query->cancel(Network::ActiveDnsQuery::CancelReason::QueryAbandoned); // Also validate that pending events are around to exercise the resource @@ -999,7 +1005,8 @@ TEST_P(DnsImplTest, DestructPending) { // just via UDP. // Either way, we have no tests today that cover parallel queries. We can do this is a follow up. TEST_P(DnsImplTest, DestructPendingAllQuery) { - ActiveDnsQuery* query = resolveWithUnreferencedParameters("", DnsLookupFamily::All, true); + ActiveDnsQuery* query = + resolveWithUnreferencedParameters("foo.bar.baz", DnsLookupFamily::All, true); ASSERT_NE(nullptr, query); } @@ -1019,12 +1026,12 @@ TEST_P(DnsImplTest, DestructCallback) { 1 /*get_addr_failure*/, 0 /*timeouts*/); } -// Validate basic success/fail lookup behavior. The empty request will connect +// Validate basic success/fail lookup behavior. The "foo.bar.baz" request will connect // to TestDnsServer, but localhost should resolve via the hosts file with no // asynchronous behavior or network events. TEST_P(DnsImplTest, LocalLookup) { std::list address_list; - EXPECT_NE(nullptr, resolveWithNoRecordsExpectation("", DnsLookupFamily::V4Only)); + EXPECT_NE(nullptr, resolveWithNoRecordsExpectation("foo.bar.baz", DnsLookupFamily::V4Only)); dispatcher_->run(Event::Dispatcher::RunType::Block); if (GetParam() == Address::IpVersion::v4) { @@ -1146,7 +1153,7 @@ TEST_P(DnsImplTest, DestroyChannelOnRefused) { server_->setRefused(true); EXPECT_NE(nullptr, - resolveWithExpectations("", DnsLookupFamily::V4Only, + resolveWithExpectations("unresolvable.name", DnsLookupFamily::V4Only, DnsResolver::ResolutionStatus::Failure, {}, {}, absl::nullopt)); dispatcher_->run(Event::Dispatcher::RunType::Block); checkStats(1 /*resolve_total*/, 0 /*pending_resolutions*/, 0 /*not_found*/, @@ -1421,6 +1428,11 @@ TEST_P(DnsImplTest, Cancel) { query->cancel(Network::ActiveDnsQuery::CancelReason::QueryAbandoned); dispatcher_->run(Event::Dispatcher::RunType::Block); + if (stats_store_.counter("dns.cares.resolve_total").value() < 4) { + // if c-ares did not read both responses at once, run another loop iteration + // to make it read the second response. + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } checkStats(4 /*resolve_total*/, 0 /*pending_resolutions*/, 3 /*not_found*/, 0 /*get_addr_failure*/, 0 /*timeouts*/); } @@ -1926,7 +1938,7 @@ TEST_P(DnsImplFilterUnroutableFamiliesDontFilterTest, DontFilterAllV6) { class DnsImplZeroTimeoutTest : public DnsImplTest { protected: - bool zeroTimeout() const override { return true; } + bool queryTimeout() const override { return true; } }; // Parameterize the DNS test server socket address. diff --git a/test/extensions/tracers/opentelemetry/http_trace_exporter_test.cc b/test/extensions/tracers/opentelemetry/http_trace_exporter_test.cc index 3674f4fec219..e4df021f593a 100644 --- a/test/extensions/tracers/opentelemetry/http_trace_exporter_test.cc +++ b/test/extensions/tracers/opentelemetry/http_trace_exporter_test.cc @@ -70,9 +70,11 @@ TEST_F(OpenTelemetryHttpTraceExporterTest, CreateExporterAndExportSpan) { Http::MockAsyncClientRequest request(&cluster_manager_.thread_local_cluster_.async_client_); Http::AsyncClient::Callbacks* callback; - EXPECT_CALL( - cluster_manager_.thread_local_cluster_.async_client_, - send_(_, _, Http::AsyncClient::RequestOptions().setTimeout(std::chrono::milliseconds(250)))) + EXPECT_CALL(cluster_manager_.thread_local_cluster_.async_client_, + send_(_, _, + Http::AsyncClient::RequestOptions() + .setTimeout(std::chrono::milliseconds(250)) + .setDiscardResponseBody(true))) .WillOnce( Invoke([&](Http::RequestMessagePtr& message, Http::AsyncClient::Callbacks& callbacks, const Http::AsyncClient::RequestOptions&) -> Http::AsyncClient::Request* { diff --git a/test/extensions/transport_sockets/http_11_proxy/BUILD b/test/extensions/transport_sockets/http_11_proxy/BUILD index c9814c9adcb4..b0138dfeedee 100644 --- a/test/extensions/transport_sockets/http_11_proxy/BUILD +++ b/test/extensions/transport_sockets/http_11_proxy/BUILD @@ -22,6 +22,7 @@ envoy_extension_cc_test( "//test/mocks/network:network_mocks", "//test/mocks/network:transport_socket_mocks", "//test/test_common:test_runtime_lib", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) diff --git a/test/extensions/transport_sockets/http_11_proxy/connect_test.cc b/test/extensions/transport_sockets/http_11_proxy/connect_test.cc index fdfc43b8b35c..816a5db8a8d1 100644 --- a/test/extensions/transport_sockets/http_11_proxy/connect_test.cc +++ b/test/extensions/transport_sockets/http_11_proxy/connect_test.cc @@ -1,3 +1,5 @@ +#include "envoy/config/core/v3/address.pb.h" + #include "source/common/buffer/buffer_impl.h" #include "source/common/network/address_impl.h" #include "source/common/network/filter_state_proxy_info.h" @@ -36,33 +38,11 @@ namespace { class Http11ConnectTest : public testing::TestWithParam { public: Http11ConnectTest() = default; - void initialize(bool no_proxy_protocol = false) { - std::string address_string = - absl::StrCat(Network::Test::getLoopbackAddressUrlString(GetParam()), ":1234"); - Network::Address::InstanceConstSharedPtr address = - Network::Utility::parseInternetAddressAndPortNoThrow(address_string); - auto info = - std::make_unique("www.foo.com", address); - if (no_proxy_protocol) { - info.reset(); - } - options_ = std::make_shared( - "", std::vector{}, std::vector{}, std::vector{}, - absl::nullopt, nullptr, std::move(info)); + void initialize(bool no_proxy_protocol = false) { initializeInternal(no_proxy_protocol, false); } - setAddress(); - auto inner_socket = std::make_unique>(); - inner_socket_ = inner_socket.get(); - EXPECT_CALL(*inner_socket_, ssl()).Times(AnyNumber()).WillRepeatedly(Return(ssl_)); - EXPECT_CALL(Const(*inner_socket_), ssl()).Times(AnyNumber()).WillRepeatedly(Return(ssl_)); - - ON_CALL(transport_callbacks_, ioHandle()).WillByDefault(ReturnRef(io_handle_)); - connect_socket_ = - std::make_unique(std::move(inner_socket), options_); - connect_socket_->setTransportSocketCallbacks(transport_callbacks_); - connect_socket_->onConnected(); - } + // Initialize the test with the proxy address provided via endpoint metadata. + void initializeWithMetadataProxyAddr() { initializeInternal(false, true); } void setAddress() { std::string address_string = @@ -75,6 +55,27 @@ class Http11ConnectTest : public testing::TestWithParamdoWrite(msg, false); + // Only the connect will be written initially. All other writes should be + // buffered in the Network::Connection buffer until the connect has been + // processed. + EXPECT_EQ(connect_data_.length(), rc1.bytes_processed_); + Network::IoResult rc2 = connect_socket_->doWrite(msg, false); + EXPECT_EQ(0, rc2.bytes_processed_); + + EXPECT_CALL(*inner_socket_, onConnected()); + connect_socket_->onConnected(); + } + Network::TransportSocketOptionsConstSharedPtr options_; NiceMock* inner_socket_; NiceMock io_handle_; @@ -83,30 +84,70 @@ class Http11ConnectTest : public testing::TestWithParam>()}; -}; -// Test injects CONNECT only once -TEST_P(Http11ConnectTest, InjectsHeaderOnlyOnce) { - initialize(); +private: + void initializeInternal(bool no_proxy_protocol, bool use_metadata_proxy_addr) { + std::string address_string = + absl::StrCat(Network::Test::getLoopbackAddressUrlString(GetParam()), ":1234"); + Network::Address::InstanceConstSharedPtr address = + Network::Utility::parseInternetAddressAndPortNoThrow(address_string); - EXPECT_CALL(io_handle_, write(BufferStringEqual(connect_data_.toString()))) - .WillOnce(Invoke([&](Buffer::Instance& buffer) { - auto length = buffer.length(); - buffer.drain(length); - return Api::IoCallUint64Result(length, Api::IoError::none()); - })); - Buffer::OwnedImpl msg("initial data"); + const std::string proxy_info_hostname = "www.foo.com"; + auto host = std::make_shared>(); + std::unique_ptr info; + + if (!no_proxy_protocol) { + if (use_metadata_proxy_addr) { + // In the case of endpoint metadata configuring the proxy address, we expect the hostname + // used to be that of the host. + connect_data_ = Buffer::OwnedImpl{ + fmt::format("CONNECT {} HTTP/1.1\r\n\r\n", host->address()->asStringView())}; + + auto metadata = std::make_shared(); + const std::string metadata_key = + Config::MetadataFilters::get().ENVOY_HTTP11_PROXY_TRANSPORT_SOCKET_ADDR; + envoy::config::core::v3::Address addr_proto; + addr_proto.mutable_socket_address()->set_address(proxy_info_hostname); + addr_proto.mutable_socket_address()->set_port_value(1234); + ProtobufWkt::Any anypb; + anypb.PackFrom(addr_proto); + metadata->mutable_typed_filter_metadata()->emplace(std::make_pair(metadata_key, anypb)); + EXPECT_CALL(*host, metadata()).Times(AnyNumber()).WillRepeatedly(Return(metadata)); + } else { + info = std::make_unique( + proxy_info_hostname, address); + setAddress(); + } + } - Network::IoResult rc1 = connect_socket_->doWrite(msg, false); - // Only the connect will be written initially. All other writes should be - // buffered in the Network::Connection buffer until the connect has been - // processed. - EXPECT_EQ(connect_data_.length(), rc1.bytes_processed_); - Network::IoResult rc2 = connect_socket_->doWrite(msg, false); - EXPECT_EQ(0, rc2.bytes_processed_); + options_ = std::make_shared( + "", std::vector{}, std::vector{}, std::vector{}, + absl::nullopt, nullptr, std::move(info)); - EXPECT_CALL(*inner_socket_, onConnected()); - connect_socket_->onConnected(); + auto inner_socket = std::make_unique>(); + inner_socket_ = inner_socket.get(); + EXPECT_CALL(*inner_socket_, ssl()).Times(AnyNumber()).WillRepeatedly(Return(ssl_)); + EXPECT_CALL(Const(*inner_socket_), ssl()).Times(AnyNumber()).WillRepeatedly(Return(ssl_)); + + ON_CALL(transport_callbacks_, ioHandle()).WillByDefault(ReturnRef(io_handle_)); + + connect_socket_ = + std::make_unique(std::move(inner_socket), options_, host); + connect_socket_->setTransportSocketCallbacks(transport_callbacks_); + connect_socket_->onConnected(); + } +}; + +// Test injects CONNECT only once. Configured via transport socket options. +TEST_P(Http11ConnectTest, InjectsHeaderOnlyOnceTransportSocketOpts) { + initialize(); + injectHeaderOnceTest(); +} + +// Test injects CONNECT only once. Configured via endpoint metadata. +TEST_P(Http11ConnectTest, InjectsHeaderOnlyOnceEndpointMetadata) { + initializeWithMetadataProxyAddr(); + injectHeaderOnceTest(); } // Test the socket is a no-op if there's no header proto. diff --git a/test/extensions/upstreams/http/udp/upstream_request_test.cc b/test/extensions/upstreams/http/udp/upstream_request_test.cc index a3fa14becf97..beb3be1d2e3d 100644 --- a/test/extensions/upstreams/http/udp/upstream_request_test.cc +++ b/test/extensions/upstreams/http/udp/upstream_request_test.cc @@ -46,7 +46,7 @@ class UdpUpstreamTest : public ::testing::Test { udp_upstream_ = std::make_unique(&mock_upstream_to_downstream_, std::move(mock_socket), std::move(mock_host), mock_dispatcher_); - EXPECT_NO_THROW(udp_upstream_->enableHalfClose()); + EXPECT_NO_THROW(udp_upstream_->enableTcpTunneling()); } protected: diff --git a/test/extensions/upstreams/tcp/generic/BUILD b/test/extensions/upstreams/tcp/generic/BUILD index 57cc2e3fcc9a..c42794c63609 100644 --- a/test/extensions/upstreams/tcp/generic/BUILD +++ b/test/extensions/upstreams/tcp/generic/BUILD @@ -17,6 +17,7 @@ envoy_cc_test( "//source/extensions/upstreams/tcp/generic:config", "//test/mocks/server:factory_context_mocks", "//test/mocks/upstream:upstream_mocks", + "//test/test_common:test_runtime_lib", "@envoy_api//envoy/extensions/filters/network/tcp_proxy/v3:pkg_cc_proto", ], ) diff --git a/test/extensions/upstreams/tcp/generic/config_test.cc b/test/extensions/upstreams/tcp/generic/config_test.cc index 08d2ff0ead46..d227607ba8fe 100644 --- a/test/extensions/upstreams/tcp/generic/config_test.cc +++ b/test/extensions/upstreams/tcp/generic/config_test.cc @@ -9,6 +9,7 @@ #include "test/mocks/tcp/mocks.h" #include "test/mocks/upstream/cluster_manager.h" #include "test/mocks/upstream/load_balancer_context.h" +#include "test/test_common/test_runtime.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -24,11 +25,20 @@ namespace Extensions { namespace Upstreams { namespace Tcp { namespace Generic { -class TcpConnPoolTest : public ::testing::Test { +class TcpConnPoolTest : public testing::TestWithParam { public: TcpConnPoolTest() { EXPECT_CALL(lb_context_, downstreamConnection()).WillRepeatedly(Return(&connection_)); } + + void SetUp() override { + scoped_runtime_.mergeValues({{"envoy.restart_features.upstream_http_filters_with_tcp_proxy", + GetParam() ? "true" : "false"}}); + } + + bool useUpstreamFilters() { return GetParam(); } + + TestScopedRuntime scoped_runtime_; NiceMock thread_local_cluster_; GenericConnPoolFactory factory_; NiceMock callbacks_; @@ -42,14 +52,17 @@ class TcpConnPoolTest : public ::testing::Test { NiceMock context_; }; -TEST_F(TcpConnPoolTest, TestNoTunnelingConfig) { +INSTANTIATE_TEST_SUITE_P(UpstreamHttpFiltersWithTunneling, TcpConnPoolTest, + ::testing::Values(true, false)); + +TEST_P(TcpConnPoolTest, TestNoTunnelingConfig) { EXPECT_CALL(thread_local_cluster_, tcpConnPool(_, _)).WillOnce(Return(absl::nullopt)); EXPECT_EQ(nullptr, factory_.createGenericConnPool( thread_local_cluster_, TcpProxy::TunnelingConfigHelperOptConstRef(), &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); } -TEST_F(TcpConnPoolTest, TestTunnelingDisabledByFilterState) { +TEST_P(TcpConnPoolTest, TestTunnelingDisabledByFilterState) { envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy_TunnelingConfig config_proto; tcp_proxy_.mutable_tunneling_config()->set_hostname("host"); const TcpProxy::TunnelingConfigHelperImpl config(scope_, tcp_proxy_, context_); @@ -65,7 +78,7 @@ TEST_F(TcpConnPoolTest, TestTunnelingDisabledByFilterState) { &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); } -TEST_F(TcpConnPoolTest, TestTunnelingNotDisabledIfFilterStateHasFalseValue) { +TEST_P(TcpConnPoolTest, TestTunnelingNotDisabledIfFilterStateHasFalseValue) { envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy_TunnelingConfig config_proto; tcp_proxy_.mutable_tunneling_config()->set_hostname("host"); const TcpProxy::TunnelingConfigHelperImpl config(scope_, tcp_proxy_, context_); @@ -75,37 +88,43 @@ TEST_F(TcpConnPoolTest, TestTunnelingNotDisabledIfFilterStateHasFalseValue) { std::make_shared(false), StreamInfo::FilterState::StateType::Mutable, StreamInfo::FilterState::LifeSpan::Connection); - EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + if (!useUpstreamFilters()) { + EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + } + EXPECT_EQ(nullptr, factory_.createGenericConnPool( thread_local_cluster_, TcpProxy::TunnelingConfigHelperOptConstRef(config), &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); } -TEST_F(TcpConnPoolTest, TestNoConnPool) { +TEST_P(TcpConnPoolTest, TestNoConnPool) { envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy_TunnelingConfig config_proto; tcp_proxy_.mutable_tunneling_config()->set_hostname("host"); const TcpProxy::TunnelingConfigHelperImpl config(scope_, tcp_proxy_, context_); - EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + if (!useUpstreamFilters()) { + EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + } EXPECT_EQ(nullptr, factory_.createGenericConnPool( thread_local_cluster_, TcpProxy::TunnelingConfigHelperOptConstRef(config), &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); } -TEST_F(TcpConnPoolTest, Http2Config) { +TEST_P(TcpConnPoolTest, Http2Config) { auto info = std::make_shared(); const std::string fake_cluster_name = "fake_cluster"; envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy_TunnelingConfig config_proto; tcp_proxy_.mutable_tunneling_config()->set_hostname("host"); const TcpProxy::TunnelingConfigHelperImpl config(scope_, tcp_proxy_, context_); - - EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + if (!useUpstreamFilters()) { + EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + } EXPECT_EQ(nullptr, factory_.createGenericConnPool( thread_local_cluster_, TcpProxy::TunnelingConfigHelperOptConstRef(config), &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); } -TEST_F(TcpConnPoolTest, Http3Config) { +TEST_P(TcpConnPoolTest, Http3Config) { auto info = std::make_shared(); const std::string fake_cluster_name = "fake_cluster"; EXPECT_CALL(*info, features()) @@ -115,7 +134,9 @@ TEST_F(TcpConnPoolTest, Http3Config) { envoy::extensions::filters::network::tcp_proxy::v3::TcpProxy_TunnelingConfig config_proto; tcp_proxy_.mutable_tunneling_config()->set_hostname("host"); const TcpProxy::TunnelingConfigHelperImpl config(scope_, tcp_proxy_, context_); - EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + if (!useUpstreamFilters()) { + EXPECT_CALL(thread_local_cluster_, httpConnPool(_, _, _)).WillOnce(Return(absl::nullopt)); + } EXPECT_EQ(nullptr, factory_.createGenericConnPool( thread_local_cluster_, TcpProxy::TunnelingConfigHelperOptConstRef(config), &lb_context_, callbacks_, decoder_callbacks_, downstream_stream_info_)); diff --git a/test/integration/BUILD b/test/integration/BUILD index bfa75687bfa1..1e2e7c57c4f8 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -347,7 +347,7 @@ envoy_cc_test_binary( "abseil_symbolize", ], deps = [ - "//source/common/formatter:formatter_extension_lib", + ":common_extensions_lib", "//source/common/http:rds_lib", "//source/exe:envoy_main_common_with_core_extensions_lib", "//source/exe:platform_impl_lib", @@ -370,7 +370,7 @@ envoy_cc_test_binary( ], linkstatic = envoy_select_linkstatic(), deps = [ - "//source/common/formatter:formatter_extension_lib", + ":common_extensions_lib", "//source/exe:main_common_lib", "//source/exe:platform_impl_lib", "//source/exe:process_wide_lib", @@ -1119,6 +1119,7 @@ envoy_cc_test_library( envoy_cc_test_library( name = "common_extensions_lib", deps = [ + "//source/common/formatter:formatter_extension_lib", "//source/common/http:rds_lib", "//source/common/router:scoped_rds_lib", "//source/extensions/clusters/eds:eds_lib", @@ -1149,7 +1150,6 @@ envoy_cc_test_library( ":utility_lib", "//source/common/common:thread_lib", "//source/common/config:api_version_lib", - "//source/common/formatter:formatter_extension_lib", "//source/common/tls:context_config_lib", "//source/common/tls:context_lib", "//source/common/tls:ssl_socket_lib", diff --git a/test/integration/filters/test_network_async_tcp_filter.cc b/test/integration/filters/test_network_async_tcp_filter.cc index 6116b2d01dc1..58c80d793153 100644 --- a/test/integration/filters/test_network_async_tcp_filter.cc +++ b/test/integration/filters/test_network_async_tcp_filter.cc @@ -41,7 +41,8 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { const test::integration::filters::TestNetworkAsyncTcpFilterConfig& config, Stats::Scope& scope, Upstream::ClusterManager& cluster_manager) : stats_(generateStats("test_network_async_tcp_filter", scope)), - cluster_name_(config.cluster_name()), cluster_manager_(cluster_manager) { + cluster_name_(config.cluster_name()), kill_after_on_data_(config.kill_after_on_data()), + cluster_manager_(cluster_manager) { const auto thread_local_cluster = cluster_manager_.getThreadLocalCluster(cluster_name_); options_ = std::make_shared(true); if (thread_local_cluster != nullptr) { @@ -60,6 +61,11 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { data.length()); client_->write(data, end_stream); + if (kill_after_on_data_) { + Tcp::AsyncTcpClient* c1 = client_.release(); + delete c1; + } + return Network::FilterStatus::StopIteration; } @@ -166,6 +172,7 @@ class TestNetworkAsyncTcpFilter : public Network::ReadFilter { TestNetworkAsyncTcpFilterStats stats_; Tcp::AsyncTcpClientPtr client_; absl::string_view cluster_name_; + bool kill_after_on_data_; std::unique_ptr request_callbacks_; std::unique_ptr downstream_callbacks_; Upstream::ClusterManager& cluster_manager_; diff --git a/test/integration/filters/test_network_async_tcp_filter.proto b/test/integration/filters/test_network_async_tcp_filter.proto index bcb4d9beee34..fc84979375bb 100644 --- a/test/integration/filters/test_network_async_tcp_filter.proto +++ b/test/integration/filters/test_network_async_tcp_filter.proto @@ -4,4 +4,5 @@ package test.integration.filters; message TestNetworkAsyncTcpFilterConfig { string cluster_name = 1; + bool kill_after_on_data = 2; } diff --git a/test/integration/integration_tcp_client.h b/test/integration/integration_tcp_client.h index 5552c928d5f9..376bf7f01a4b 100644 --- a/test/integration/integration_tcp_client.h +++ b/test/integration/integration_tcp_client.h @@ -45,6 +45,7 @@ class IntegrationTcpClient { ABSL_MUST_USE_RESULT AssertionResult write(const std::string& data, bool end_stream = false, bool verify = true, std::chrono::milliseconds timeout = TestUtility::DefaultTimeout); + const std::string& data() { return payload_reader_->data(); } bool connected() const { return !disconnected_; } // clear up to the `count` number of bytes of received data diff --git a/test/integration/load_balancers/custom_lb_policy.h b/test/integration/load_balancers/custom_lb_policy.h index e7e129852b41..e7992df16153 100644 --- a/test/integration/load_balancers/custom_lb_policy.h +++ b/test/integration/load_balancers/custom_lb_policy.h @@ -73,7 +73,8 @@ class CustomLbFactory : public Upstream::TypedLoadBalancerFactoryBase< return std::make_unique(); } - Upstream::LoadBalancerConfigPtr loadConfig(const Protobuf::Message&, + Upstream::LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, + const Protobuf::Message&, ProtobufMessage::ValidationVisitor&) override { return std::make_unique(); } diff --git a/test/integration/overload_integration_test.cc b/test/integration/overload_integration_test.cc index b4faa482411e..d3a62cdb2ff9 100644 --- a/test/integration/overload_integration_test.cc +++ b/test/integration/overload_integration_test.cc @@ -381,7 +381,6 @@ TEST_P(OverloadScaledTimerIntegrationTest, HTTP3CloseIdleHttpConnectionsDuringHa return; } TestScopedRuntime scoped_runtime; - scoped_runtime.mergeValues({{"envoy.reloadable_features.quic_fix_filter_manager_uaf", "true"}}); config_helper_.addConfigModifier([](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { auto* proof_source_config = bootstrap.mutable_static_resources() diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index 261ddd3c430e..90edb9b80931 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -2858,6 +2858,69 @@ TEST_P(ProtocolIntegrationTest, TestDownstreamResetIdleTimeout) { EXPECT_THAT(waitForAccessLog(access_log_name_), Not(HasSubstr("DPE"))); } +// Test that with http1_safe_max_connection_duration set to true, drain_timeout is not used for +// http1 connections after max_connection_duration is reached. Instead, envoy waits for the next +// request, adds connection:close to the response headers, then closes the connection after the +// stream ends. +TEST_P(ProtocolIntegrationTest, Http1SafeConnDurationTimeout) { + config_helper_.setDownstreamMaxConnectionDuration(std::chrono::milliseconds(500)); + config_helper_.addConfigModifier( + [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) { + hcm.mutable_drain_timeout()->set_nanos(1'000'000 /*=1ms*/); + hcm.set_http1_safe_max_connection_duration(true); + }); + initialize(); + + codec_client_ = makeRawHttpConnection(makeClientConnection(lookupPort("http")), absl::nullopt); + + auto response = codec_client_->makeRequestWithBody(default_request_headers_, 1024); + waitForNextUpstreamRequest(); + + upstream_request_->encodeHeaders(default_response_headers_, true); + ASSERT_TRUE(response->waitForEndStream()); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response->complete()); + test_server_->waitForCounterGe("cluster.cluster_0.upstream_cx_total", 1); + test_server_->waitForCounterGe("cluster.cluster_0.upstream_rq_200", 1); + + if (downstream_protocol_ != Http::CodecType::HTTP1) { + ASSERT_TRUE(codec_client_->waitForDisconnect(std::chrono::milliseconds(10000))); + test_server_->waitForCounterGe("http.config_test.downstream_cx_max_duration_reached", 1); + EXPECT_EQ(test_server_->gauge("http.config_test.downstream_cx_http1_soft_drain")->value(), 0); + // The rest of the test is only for http1. + return; + } + + // Wait until after the max connection duration + test_server_->waitForCounterGe("http.config_test.downstream_cx_max_duration_reached", 1); + test_server_->waitForGaugeGe("http.config_test.downstream_cx_http1_soft_drain", 1); + + // Envoy now waits for one more request/response over this connection before sending the + // connection:close header and closing the connection. No matter how long the request/response + // takes, envoy will not close the connection until it's able to send the connection:close header + // downstream in a response. + // + // Sleeping for longer than the drain phase duration just to show it is no longer relevant. + absl::SleepFor(absl::Seconds(1)); + + auto soft_drain_response = codec_client_->makeRequestWithBody(default_request_headers_, 1024); + waitForNextUpstreamRequest(); + + upstream_request_->encodeHeaders(default_response_headers_, true); + ASSERT_TRUE(soft_drain_response->waitForEndStream()); + // Envoy will close the connection after the response has been sent. + ASSERT_TRUE(codec_client_->waitForDisconnect(std::chrono::milliseconds(10000))); + + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(soft_drain_response->complete()); + + // The client must have been notified that the connection will be closed. + EXPECT_EQ(soft_drain_response->headers().getConnectionValue(), + Http::Headers::get().ConnectionValues.Close); +} + // Test connection is closed after single request processed. TEST_P(ProtocolIntegrationTest, ConnDurationTimeoutBasic) { config_helper_.setDownstreamMaxConnectionDuration(std::chrono::milliseconds(500)); @@ -3039,6 +3102,95 @@ TEST_P(DownstreamProtocolIntegrationTest, MaxRequestsPerConnectionReached) { ASSERT_TRUE(codec_client_->waitForDisconnect()); } +// Test that onDrainTimeout allows current stream to finish before closing connection for http1. +TEST_P(DownstreamProtocolIntegrationTest, MaxRequestsPerConnectionVsMaxConnectionDuration) { + config_helper_.setDownstreamMaxRequestsPerConnection(2); + config_helper_.setDownstreamMaxConnectionDuration(std::chrono::milliseconds(500)); + config_helper_.addConfigModifier( + [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) { hcm.mutable_drain_timeout()->set_nanos(500'000'000 /*=500ms*/); }); + + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 0); + EXPECT_EQ(test_server_->counter("http.config_test.downstream_cx_max_requests_reached")->value(), + 0); + + test_server_->waitForCounterGe("http.config_test.downstream_cx_max_duration_reached", 1); + // http1 is not closed at this point because envoy needs to send a response with the + // connection:close response header to be able to safely close the connection. For other protocols + // it's safe for envoy to just close the connection, so they do so. + if (downstream_protocol_ != Http::CodecType::HTTP1) { + ASSERT_TRUE(codec_client_->waitForDisconnect()); + EXPECT_TRUE(codec_client_->sawGoAway()); + // The rest of the test is only for http1. + return; + } + + // Sending second request. + auto response_2 = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + + // Before sending the response, sleep past the drain timer. Nothing should happen. + timeSystem().advanceTimeWait(Seconds(1)); + EXPECT_FALSE(codec_client_->sawGoAway()); + + upstream_request_->encodeHeaders(default_response_headers_, true); + ASSERT_TRUE(codec_client_->waitForDisconnect()); + + ASSERT_TRUE(response_2->waitForEndStream()); + EXPECT_TRUE(upstream_request_->complete()); + EXPECT_TRUE(response_2->complete()); + EXPECT_EQ(test_server_->counter("http.config_test.downstream_cx_max_requests_reached")->value(), + 1); + + if (downstream_protocol_ == Http::CodecType::HTTP1) { + ASSERT_NE(nullptr, response_2->headers().Connection()); + EXPECT_EQ("close", response_2->headers().getConnectionValue()); + } else { + EXPECT_TRUE(codec_client_->sawGoAway()); + } + ASSERT_TRUE(codec_client_->waitForDisconnect()); +} + +// Test that max stream duration still works after max requests per connection is reached (i.e. the +// final response is still time bounded). Also, if if max_stream_duration is triggered, it should +// add the connection:close header if the downstream protocol is http1 and this will be the last +// response! +TEST_P(DownstreamProtocolIntegrationTest, MaxRequestsPerConnectionVsMaxStreamDuration) { + config_helper_.setDownstreamMaxRequestsPerConnection(2); + config_helper_.setDownstreamMaxStreamDuration(std::chrono::milliseconds(500)); + + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + // Sending first request and waiting to complete the response. + sendRequestAndWaitForResponse(default_request_headers_, 0, default_response_headers_, 0); + EXPECT_EQ(test_server_->counter("http.config_test.downstream_cx_max_requests_reached")->value(), + 0); + + // Sending second request and waiting to complete the response. + auto response_2 = codec_client_->makeHeaderOnlyRequest(default_request_headers_); + waitForNextUpstreamRequest(); + EXPECT_EQ(test_server_->counter("http.config_test.downstream_cx_max_requests_reached")->value(), + 1); + + // Don't send a response. HCM should sendLocalReply after max stream duration has elapsed. + test_server_->waitForCounterGe("http.config_test.downstream_rq_max_duration_reached", 1); + + if (downstream_protocol_ == Http::CodecType::HTTP1) { + ASSERT_TRUE(codec_client_->waitForDisconnect()); + ASSERT_TRUE(response_2->complete()); + // This will be the last request / response; envoy's going to close the connection after this + // stream ends. We should notify the client. + EXPECT_EQ("close", response_2->headers().getConnectionValue()); + } else { + ASSERT_TRUE(response_2->waitForEndStream()); + codec_client_->close(); + } +} + // Make sure that invalid authority headers get blocked at or before the HCM. TEST_P(DownstreamProtocolIntegrationTest, InvalidAuthority) { disable_client_header_validation_ = true; diff --git a/test/integration/quic_http_integration_test.cc b/test/integration/quic_http_integration_test.cc index 9f0cc45724a7..538b88a82b07 100644 --- a/test/integration/quic_http_integration_test.cc +++ b/test/integration/quic_http_integration_test.cc @@ -2258,15 +2258,8 @@ TEST_P(QuicHttpIntegrationSPATest, UsesPreferredAddressDualStack) { ASSERT_TRUE(response->complete()); EXPECT_EQ("127.0.0.2", quic_connection_->peer_address().host().ToString()); - if (Runtime::runtimeFeatureEnabled("envoy.restart_features.udp_read_normalize_addresses")) { - test_server_->waitForCounterGe( - "listener.[__]_0.quic.connection.num_packets_rx_on_preferred_address", 2u); - } else { - EXPECT_EQ( - 0u, - test_server_->counter("listener.[__]_0.quic.connection.num_packets_rx_on_preferred_address") - ->value()); - } + test_server_->waitForCounterGe( + "listener.[__]_0.quic.connection.num_packets_rx_on_preferred_address", 2u); } TEST_P(QuicHttpIntegrationTest, PreferredAddressDroppedByIncompatibleListenerFilter) { @@ -2421,12 +2414,10 @@ TEST_P(QuicHttpIntegrationTest, ConnectionDebugVisitor) { EXPECT_TRUE(response->waitForEndStream()); ASSERT_TRUE(response->complete()); - // TODO(https://github.com/envoyproxy/envoy/issues/34492) fix - return; EnvoyQuicClientSession* quic_session = static_cast(codec_client_->connection()); std::string listener = version_ == Network::Address::IpVersion::v4 ? "127.0.0.1_0" : "[__1]_0"; - EXPECT_LOG_CONTAINS( + WAIT_FOR_LOG_CONTAINS( "info", fmt::format("Quic connection from {} with id {} closed {} with details:", quic_connection_->self_address().ToString(), diff --git a/test/integration/redirect_integration_test.cc b/test/integration/redirect_integration_test.cc index db289c321775..51537b20bbcf 100644 --- a/test/integration/redirect_integration_test.cc +++ b/test/integration/redirect_integration_test.cc @@ -208,68 +208,9 @@ TEST_P(RedirectIntegrationTest, BasicInternalRedirect) { EXPECT_THAT(waitForAccessLog(access_log_name_, 1), HasSubstr("200 via_upstream -")); } -// Test the buggy behavior where Envoy doesn't respond to "Connection: close" header in requests -// which get redirected. -// TODO(danzh) remove the test once the runtime guard is deprecated. -TEST_P(RedirectIntegrationTest, ConnectionCloseHeaderDroppedInInternalRedirect) { - config_helper_.addRuntimeOverride( - "envoy.reloadable_features.http1_connection_close_header_in_redirect", "false"); - - if (downstreamProtocol() != Envoy::Http::CodecClient::Type::HTTP1) { - return; - } - useAccessLog("%RESPONSE_FLAGS% %RESPONSE_CODE% %RESPONSE_CODE_DETAILS% %RESP(test-header)%"); - // Validate that header sanitization is only called once. - config_helper_.addConfigModifier( - [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& - hcm) { - // The delay should be ignored in light of "Connection: close". - hcm.mutable_delayed_close_timeout()->set_seconds(1); - hcm.set_via("via_value"); - hcm.mutable_common_http_protocol_options() - ->mutable_max_requests_per_connection() - ->set_value(10); - }); - initialize(); - - codec_client_ = makeHttpConnection(lookupPort("http")); - - default_request_headers_.setHost("handle.internal.redirect"); - default_request_headers_.setConnection("close"); - IntegrationStreamDecoderPtr response = - codec_client_->makeHeaderOnlyRequest(default_request_headers_); - - waitForNextUpstreamRequest(); - - upstream_request_->encodeHeaders(redirect_response_, true); - EXPECT_THAT(waitForAccessLog(access_log_name_, 0), - HasSubstr("302 internal_redirect test-header-value")); - - waitForNextUpstreamRequest(); - ASSERT(upstream_request_->headers().EnvoyOriginalUrl() != nullptr); - EXPECT_EQ("http://handle.internal.redirect/test/long/url", - upstream_request_->headers().getEnvoyOriginalUrlValue()); - EXPECT_EQ("/new/url", upstream_request_->headers().getPathValue()); - EXPECT_EQ("authority2", upstream_request_->headers().getHostValue()); - EXPECT_EQ("via_value", upstream_request_->headers().getViaValue()); - - upstream_request_->encodeHeaders(default_response_headers_, true); - - ASSERT_TRUE(response->waitForEndStream()); - ASSERT_TRUE(response->complete()); - EXPECT_EQ("200", response->headers().getStatusValue()); - EXPECT_TRUE(response->headers().get(Envoy::Http::Headers::get().Connection).empty()); - - // Envoy won't close the connection with out the fix. - ASSERT_FALSE(codec_client_->waitForDisconnect(std::chrono::milliseconds(2000))); -} - // Test that Envoy should correctly respond to "Connection: close" header in requests which get // redirected by echoing "Connection: close" in response and closing the connection immediately. TEST_P(RedirectIntegrationTest, ConnectionCloseHeaderHonoredInInternalRedirect) { - config_helper_.addRuntimeOverride( - "envoy.reloadable_features.http1_connection_close_header_in_redirect", "true"); - if (downstreamProtocol() != Envoy::Http::CodecClient::Type::HTTP1) { return; } diff --git a/test/integration/tcp_async_client_integration_test.cc b/test/integration/tcp_async_client_integration_test.cc index 89c4e29c1771..f0a9932bbc0a 100644 --- a/test/integration/tcp_async_client_integration_test.cc +++ b/test/integration/tcp_async_client_integration_test.cc @@ -1,3 +1,4 @@ +#include "test/integration/filters/test_network_async_tcp_filter.pb.h" #include "test/integration/integration.h" #include "gtest/gtest.h" @@ -16,15 +17,37 @@ class TcpAsyncClientIntegrationTest : public testing::TestWithParam void { + test::integration::filters::TestNetworkAsyncTcpFilterConfig proto_config; + TestUtility::loadFromYaml(yaml, proto_config); + + auto* listener = bootstrap.mutable_static_resources()->mutable_listeners(0); + auto* filter_chain = listener->mutable_filter_chains(0); + auto* filter = filter_chain->mutable_filters(0); + filter->mutable_typed_config()->PackFrom(proto_config); + }); + + BaseIntegrationTest::initialize(); + } }; INSTANTIATE_TEST_SUITE_P(IpVersions, TcpAsyncClientIntegrationTest, testing::ValuesIn(TestEnvironment::getIpVersionsForTest())); TEST_P(TcpAsyncClientIntegrationTest, SingleRequest) { - enableHalfClose(true); - initialize(); + init(); std::string request("request"); std::string response("response"); @@ -51,8 +74,7 @@ TEST_P(TcpAsyncClientIntegrationTest, SingleRequest) { } TEST_P(TcpAsyncClientIntegrationTest, MultipleRequestFrames) { - enableHalfClose(true); - initialize(); + init(); std::string data_frame_1("data_frame_1"); std::string data_frame_2("data_frame_2"); @@ -85,8 +107,7 @@ TEST_P(TcpAsyncClientIntegrationTest, MultipleRequestFrames) { } TEST_P(TcpAsyncClientIntegrationTest, MultipleResponseFrames) { - enableHalfClose(true); - initialize(); + init(); std::string data_frame_1("data_frame_1"); std::string response_1("response_1"); @@ -116,8 +137,7 @@ TEST_P(TcpAsyncClientIntegrationTest, Reconnect) { return; } - enableHalfClose(true); - initialize(); + init(); IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); ASSERT_TRUE(tcp_client->write("hello1", false)); @@ -143,11 +163,24 @@ TEST_P(TcpAsyncClientIntegrationTest, Reconnect) { test_server_->waitForGaugeEq("cluster.cluster_0.upstream_cx_active", 0); } +TEST_P(TcpAsyncClientIntegrationTest, ClientTearDown) { + init(true); + + std::string request("request"); + + IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("listener_0")); + ASSERT_TRUE(tcp_client->write(request, true)); + FakeRawConnectionPtr fake_upstream_connection; + ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection)); + ASSERT_TRUE(fake_upstream_connection->waitForData(request.size())); + + tcp_client->close(); +} + #if ENVOY_PLATFORM_ENABLE_SEND_RST // Test if RST close can be detected from downstream and upstream is closed by RST. TEST_P(TcpAsyncClientIntegrationTest, TestClientCloseRST) { - enableHalfClose(true); - initialize(); + init(); std::string request("request"); std::string response("response"); @@ -178,8 +211,7 @@ TEST_P(TcpAsyncClientIntegrationTest, TestClientCloseRST) { // Test if RST close can be detected from upstream. TEST_P(TcpAsyncClientIntegrationTest, TestUpstreamCloseRST) { - enableHalfClose(true); - initialize(); + init(); std::string request("request"); std::string response("response"); @@ -212,8 +244,7 @@ TEST_P(TcpAsyncClientIntegrationTest, TestUpstreamCloseRST) { // the client. The behavior is different for windows, since RST support is literally supported for // unix like system, disabled the test for windows. TEST_P(TcpAsyncClientIntegrationTest, TestDownstremHalfClosedThenRST) { - enableHalfClose(true); - initialize(); + init(); std::string request("request"); std::string response("response"); diff --git a/test/mocks/grpc/mocks.h b/test/mocks/grpc/mocks.h index bd9287102642..d1d41f211115 100644 --- a/test/mocks/grpc/mocks.h +++ b/test/mocks/grpc/mocks.h @@ -39,6 +39,7 @@ class MockAsyncStream : public RawAsyncStream { MOCK_METHOD(void, resetStream, ()); MOCK_METHOD(bool, isAboveWriteBufferHighWatermark, (), (const)); MOCK_METHOD(const StreamInfo::StreamInfo&, streamInfo, (), (const)); + MOCK_METHOD(StreamInfo::StreamInfo&, streamInfo, (), ()); MOCK_METHOD(void, setWatermarkCallbacks, (Http::SidestreamWatermarkCallbacks&)); MOCK_METHOD(void, removeWatermarkCallbacks, ()); }; diff --git a/test/mocks/http/http_server_properties_cache.h b/test/mocks/http/http_server_properties_cache.h index 2eced57f9f87..d29ed5ce1cb5 100644 --- a/test/mocks/http/http_server_properties_cache.h +++ b/test/mocks/http/http_server_properties_cache.h @@ -21,6 +21,7 @@ class MockHttpServerPropertiesCache : public HttpServerPropertiesCache { MOCK_METHOD(size_t, size, (), (const)); MOCK_METHOD(HttpServerPropertiesCache::Http3StatusTracker&, getOrCreateHttp3StatusTracker, (const Origin& origin)); + MOCK_METHOD(void, resetBrokenness, ()); }; class MockHttpServerPropertiesCacheManager : public HttpServerPropertiesCacheManager { @@ -30,6 +31,7 @@ class MockHttpServerPropertiesCacheManager : public HttpServerPropertiesCacheMan MOCK_METHOD(HttpServerPropertiesCacheSharedPtr, getCache, (const envoy::config::core::v3::AlternateProtocolsCacheOptions& config, Event::Dispatcher& dispatcher)); + MOCK_METHOD(void, forEachThreadLocalCache, (HttpServerPropertiesCacheManager::CacheFn)); }; } // namespace Http diff --git a/test/mocks/http/mocks.h b/test/mocks/http/mocks.h index a09d7f283a01..cdf2690c2a1c 100644 --- a/test/mocks/http/mocks.h +++ b/test/mocks/http/mocks.h @@ -209,7 +209,7 @@ class MockFilterChainFactory : public FilterChainFactory { MOCK_METHOD(bool, createFilterChain, (FilterChainManager & manager), (const)); MOCK_METHOD(bool, createUpgradeFilterChain, (absl::string_view upgrade_type, const FilterChainFactory::UpgradeMap* upgrade_map, - FilterChainManager& manager, const Http::FilterChainOptions&), + FilterChainManager& manager, const FilterChainOptions&), (const)); }; @@ -577,6 +577,7 @@ class MockAsyncClientStream : public virtual AsyncClient::Stream { (override)); MOCK_METHOD(void, removeWatermarkCallbacks, (), (override)); MOCK_METHOD(const StreamInfo::StreamInfo&, streamInfo, (), (const override)); + MOCK_METHOD(StreamInfo::StreamInfo&, streamInfo, (), (override)); private: absl::optional destructor_callback_; @@ -638,6 +639,7 @@ class MockConnectionManagerConfig : public ConnectionManagerConfig { MOCK_METHOD(absl::optional, idleTimeout, (), (const)); MOCK_METHOD(bool, isRoutable, (), (const)); MOCK_METHOD(absl::optional, maxConnectionDuration, (), (const)); + MOCK_METHOD(bool, http1SafeMaxConnectionDuration, (), (const)); MOCK_METHOD(absl::optional, maxStreamDuration, (), (const)); MOCK_METHOD(std::chrono::milliseconds, streamIdleTimeout, (), (const)); MOCK_METHOD(std::chrono::milliseconds, requestTimeout, (), (const)); diff --git a/test/mocks/router/mocks.cc b/test/mocks/router/mocks.cc index c321bfe1574f..8a3ae1c7b6bf 100644 --- a/test/mocks/router/mocks.cc +++ b/test/mocks/router/mocks.cc @@ -99,6 +99,10 @@ MockPathMatchCriterion::~MockPathMatchCriterion() = default; MockRouteEntry::MockRouteEntry() { ON_CALL(*this, clusterName()).WillByDefault(ReturnRef(cluster_name_)); + ON_CALL(*this, getRequestHostValue(_)) + .WillByDefault([](const Http::RequestHeaderMap& headers) -> std::string { + return std::string(headers.getHostValue()); + }); ON_CALL(*this, opaqueConfig()).WillByDefault(ReturnRef(opaque_config_)); ON_CALL(*this, rateLimitPolicy()).WillByDefault(ReturnRef(rate_limit_policy_)); ON_CALL(*this, retryPolicy()).WillByDefault(ReturnRef(retry_policy_)); diff --git a/test/mocks/router/mocks.h b/test/mocks/router/mocks.h index ca84f36654f4..1fcadf99f811 100644 --- a/test/mocks/router/mocks.h +++ b/test/mocks/router/mocks.h @@ -412,6 +412,8 @@ class MockRouteEntry : public RouteEntry { // Router::Config MOCK_METHOD(const std::string&, clusterName, (), (const)); + MOCK_METHOD(const std::string, getRequestHostValue, (const Http::RequestHeaderMap& headers), + (const)); MOCK_METHOD(Http::Code, clusterNotFoundResponseCode, (), (const)); MOCK_METHOD(void, finalizeRequestHeaders, (Http::RequestHeaderMap & headers, const StreamInfo::StreamInfo& stream_info, diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index 211c7afae603..69e27613edae 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -46,8 +46,11 @@ class MockConnectionInfo : public ConnectionInfo { MOCK_METHOD(bool, peerCertificateValidated, (), (const)); MOCK_METHOD(absl::Span, uriSanLocalCertificate, (), (const)); MOCK_METHOD(const std::string&, sha256PeerCertificateDigest, (), (const)); + MOCK_METHOD(absl::Span, sha256PeerCertificateChainDigests, (), (const)); MOCK_METHOD(const std::string&, sha1PeerCertificateDigest, (), (const)); + MOCK_METHOD(absl::Span, sha1PeerCertificateChainDigests, (), (const)); MOCK_METHOD(const std::string&, serialNumberPeerCertificate, (), (const)); + MOCK_METHOD(absl::Span, serialNumbersPeerCertificates, (), (const)); MOCK_METHOD(const std::string&, issuerPeerCertificate, (), (const)); MOCK_METHOD(const std::string&, subjectPeerCertificate, (), (const)); MOCK_METHOD(absl::Span, uriSanPeerCertificate, (), (const)); diff --git a/test/mocks/stream_info/mocks.h b/test/mocks/stream_info/mocks.h index d1c2df8d0fef..fc81b0fcf6d6 100644 --- a/test/mocks/stream_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -172,6 +172,9 @@ class MockStreamInfo : public StreamInfo { MOCK_METHOD(void, setShouldSchemeMatchUpstream, (bool)); MOCK_METHOD(bool, shouldDrainConnectionUponCompletion, (), (const)); MOCK_METHOD(void, setShouldDrainConnectionUponCompletion, (bool)); + MOCK_METHOD(void, setParentStreamInfo, (const StreamInfo&), ()); + MOCK_METHOD(void, clearParentStreamInfo, ()); + MOCK_METHOD(OptRef, parentStreamInfo, (), (const)); Envoy::Event::SimulatedTimeSystem ts_; SystemTime start_time_; diff --git a/test/mocks/upstream/cluster_info.cc b/test/mocks/upstream/cluster_info.cc index 4038e57bd8c1..380c7a7c8bcd 100644 --- a/test/mocks/upstream/cluster_info.cc +++ b/test/mocks/upstream/cluster_info.cc @@ -171,6 +171,11 @@ MockClusterInfo::MockClusterInfo() protocol, codecStats(protocol)) : nullptr; })); + ON_CALL(*this, lrsReportMetricNames()) + .WillByDefault(Invoke([this]() -> OptRef { + return makeOptRefFromPtr( + lrs_report_metric_names_.get()); + })); } MockClusterInfo::~MockClusterInfo() = default; diff --git a/test/mocks/upstream/cluster_info.h b/test/mocks/upstream/cluster_info.h index d9ec12addef6..8f5a72973f49 100644 --- a/test/mocks/upstream/cluster_info.h +++ b/test/mocks/upstream/cluster_info.h @@ -172,6 +172,7 @@ class MockClusterInfo : public ClusterInfo { MOCK_METHOD( OptRef, happyEyeballsConfig, (), (const)); + MOCK_METHOD(OptRef>, lrsReportMetricNames, (), (const)); ::Envoy::Http::HeaderValidatorStats& codecStats(Http::Protocol protocol) const; Http::Http1::CodecStats& http1CodecStats() const override; Http::Http2::CodecStats& http2CodecStats() const override; @@ -235,6 +236,7 @@ class MockClusterInfo : public ClusterInfo { Http::HeaderValidatorFactoryPtr header_validator_factory_; absl::optional happy_eyeballs_config_; + const std::unique_ptr lrs_report_metric_names_; }; class MockIdleTimeEnabledClusterInfo : public MockClusterInfo { diff --git a/test/mocks/upstream/host.h b/test/mocks/upstream/host.h index e67f0a5ea6a5..46460eaf9e8e 100644 --- a/test/mocks/upstream/host.h +++ b/test/mocks/upstream/host.h @@ -89,6 +89,7 @@ class MockHostDescription : public HostDescription { MOCK_METHOD(void, canary, (bool new_canary)); MOCK_METHOD(MetadataConstSharedPtr, metadata, (), (const)); MOCK_METHOD(void, metadata, (MetadataConstSharedPtr)); + MOCK_METHOD(const MetadataConstSharedPtr, localityMetadata, (), (const)); MOCK_METHOD(const ClusterInfo&, cluster, (), (const)); MOCK_METHOD(bool, canCreateConnection, (Upstream::ResourcePriority), (const)); MOCK_METHOD(Outlier::DetectorHostMonitor&, outlierDetector, (), (const)); @@ -165,6 +166,7 @@ class MockHostLight : public Host { MOCK_METHOD(bool, canary, (), (const)); MOCK_METHOD(void, canary, (bool new_canary)); MOCK_METHOD(MetadataConstSharedPtr, metadata, (), (const)); + MOCK_METHOD(const MetadataConstSharedPtr, localityMetadata, (), (const)); MOCK_METHOD(void, metadata, (MetadataConstSharedPtr)); MOCK_METHOD(const ClusterInfo&, cluster, (), (const)); MOCK_METHOD(bool, canCreateConnection, (Upstream::ResourcePriority), (const)); diff --git a/test/mocks/upstream/load_balancer.h b/test/mocks/upstream/load_balancer.h index 5edbd0d06b73..12cb0b7732fc 100644 --- a/test/mocks/upstream/load_balancer.h +++ b/test/mocks/upstream/load_balancer.h @@ -25,5 +25,13 @@ class MockLoadBalancer : public LoadBalancer { std::shared_ptr host_{new MockHost()}; }; + +class MockLoadBalancerFactoryContext : public LoadBalancerFactoryContext { +public: + MockLoadBalancerFactoryContext() = default; + ~MockLoadBalancerFactoryContext() = default; + MOCK_METHOD(Event::Dispatcher&, mainThreadDispatcher, ()); +}; + } // namespace Upstream } // namespace Envoy diff --git a/test/mocks/upstream/typed_load_balancer_factory.h b/test/mocks/upstream/typed_load_balancer_factory.h index 5efc47d47c3b..9cc82b98266e 100644 --- a/test/mocks/upstream/typed_load_balancer_factory.h +++ b/test/mocks/upstream/typed_load_balancer_factory.h @@ -26,7 +26,7 @@ class MockTypedLoadBalancerFactory : public TypedLoadBalancerFactory { const PrioritySet& priority_set, Runtime::Loader& runtime, Random::RandomGenerator& random, TimeSource& time_source)); - LoadBalancerConfigPtr loadConfig(const Protobuf::Message&, + LoadBalancerConfigPtr loadConfig(Upstream::LoadBalancerFactoryContext&, const Protobuf::Message&, ProtobufMessage::ValidationVisitor&) override { return std::make_unique(); } diff --git a/test/per_file_coverage.sh b/test/per_file_coverage.sh index 5258c8403c84..6cca2bbba585 100755 --- a/test/per_file_coverage.sh +++ b/test/per_file_coverage.sh @@ -6,23 +6,22 @@ declare -a KNOWN_LOW_COVERAGE=( "source/common:96.2" "source/common/api:84.5" # flaky due to posix: be careful adjusting "source/common/api/posix:83.8" # flaky (accept failover non-deterministic): be careful adjusting -"source/common/config:95.8" +"source/common/config:96.1" "source/common/crypto:95.5" "source/common/event:95.1" # Emulated edge events guards don't report LCOV "source/common/filesystem/posix:96.3" # FileReadToEndNotReadable fails in some env; createPath can't test all failure branches. -"source/common/http/http2:95.9" +"source/common/http/http2:96.0" "source/common/json:94.8" "source/common/matcher:94.4" "source/common/memory:74.5" # tcmalloc code path is not enabled in coverage build, only gperf tcmalloc, see PR#32589 "source/common/network:94.4" # Flaky, `activateFileEvents`, `startSecureTransport` and `ioctl`, listener_socket do not always report LCOV "source/common/network/dns_resolver:91.4" # A few lines of MacOS code not tested in linux scripts. Tested in MacOS scripts -"source/common/quic:93.7" +"source/common/quic:93.8" "source/common/secret:95.4" "source/common/signal:87.2" # Death tests don't report LCOV "source/common/thread:0.0" # Death tests don't report LCOV "source/common/watchdog:58.6" # Death tests don't report LCOV "source/exe:94.2" # increased by #32346, need coverage for terminate_handler and hot restart failures -"source/extensions/clusters/common:95.6" "source/extensions/common:93.0" #flaky: be careful adjusting "source/extensions/common/proxy_protocol:93.8" # Adjusted for security patch "source/extensions/common/tap:94.6" @@ -31,7 +30,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/filters/common/fault:94.5" "source/extensions/filters/common/rbac:90.8" "source/extensions/filters/http/cache:95.1" -"source/extensions/filters/http/grpc_json_transcoder:93.8" # TODO(#28232) +"source/extensions/filters/http/grpc_json_transcoder:94.2" # TODO(#28232) "source/extensions/filters/http/ip_tagging:88.2" "source/extensions/filters/http/kill_request:91.7" # Death tests don't report LCOV "source/extensions/filters/http/wasm:1.3" # Disabled due to issue (#24164) @@ -44,14 +43,11 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/rate_limit_descriptors/expr:95.0" "source/extensions/stat_sinks/graphite_statsd:82.8" # Death tests don't report LCOV "source/extensions/stat_sinks/statsd:85.2" # Death tests don't report LCOV -"source/extensions/tracers:96.5" -"source/extensions/tracers/common:75.0" -"source/extensions/tracers/common/ot:73.1" "source/extensions/tracers/opencensus:94.0" "source/extensions/tracers/zipkin:95.8" "source/extensions/transport_sockets:97.4" -"source/common/tls:94.7" -"source/common/tls/cert_validator:94.2" +"source/common/tls:94.8" +"source/common/tls/cert_validator:94.4" "source/common/tls/private_key:88.9" "source/extensions/wasm_runtime/wamr:0.0" # Not enabled in coverage build "source/extensions/wasm_runtime/wasmtime:0.0" # Not enabled in coverage build @@ -60,7 +56,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/listener_managers/validation_listener_manager:70.5" "source/extensions/watchdog/profile_action:83.3" "source/server:91.0" # flaky: be careful adjusting. See https://github.com/envoyproxy/envoy/issues/15239 -"source/server/config_validation:91.4" +"source/server/config_validation:91.8" "source/extensions/health_checkers:96.1" "source/extensions/health_checkers/http:93.9" "source/extensions/health_checkers/grpc:92.1" diff --git a/test/proto/BUILD b/test/proto/BUILD index b3d1a6ffca59..81de53e0a69c 100644 --- a/test/proto/BUILD +++ b/test/proto/BUILD @@ -65,6 +65,21 @@ envoy_proto_descriptor( ], ) +envoy_proto_library( + name = "logging_proto", + srcs = [ + "logging.proto", + ], +) + +envoy_proto_descriptor( + name = "logging_proto_descriptor", + srcs = [ + "logging.proto", + ], + out = "logging.descriptor", +) + envoy_proto_library( name = "sensitive_proto", srcs = [":sensitive.proto"], diff --git a/test/proto/apikeys.proto b/test/proto/apikeys.proto index a38bbd6f65dc..d292f7ad7d42 100644 --- a/test/proto/apikeys.proto +++ b/test/proto/apikeys.proto @@ -94,6 +94,8 @@ message RepeatedSupportedTypes { repeated float float = 12; repeated double double = 13; + + map map = 14; } message UnsupportedTypes { diff --git a/test/proto/logging.proto b/test/proto/logging.proto new file mode 100644 index 000000000000..15d56aea9126 --- /dev/null +++ b/test/proto/logging.proto @@ -0,0 +1,111 @@ +syntax = "proto3"; + +package logging; + +message TestBucket { + string name = 1; + float ratio = 2; + repeated bytes objects = 3; +} + +enum TestEnum { + TEST_ENUM_UNSPECIFIED = 0; + ALPHA = 1; + BETA = 2; + GAMMA = 3; +} + +enum TestProto2Enum { + PROTO2_ALPHA = 0; + PROTO2_BETA = 1; + PROTO2_GAMMA = 2; +} + +message TestProto2Message { + repeated string repeated_strings = 3; + + repeated TestProto2Enum repeated_enum = 17 [packed = true]; + + repeated double repeated_double = 4; + + repeated float repeated_float = 5 [packed = true]; + + repeated int64 repeated_int64 = 6; + + repeated uint64 repeated_uint64 = 7 [packed = true]; + + repeated int32 repeated_int32 = 8; + + repeated fixed64 repeated_fixed64 = 9 [packed = true]; + + repeated fixed32 repeated_fixed32 = 10; + + repeated bool repeated_bool = 11 [packed = true]; + + repeated uint32 repeated_uint32 = 12; + + repeated sfixed64 repeated_sfixed64 = 13 [packed = true]; + + repeated sfixed32 repeated_sfixed32 = 14; + + repeated sint32 repeated_sint32 = 15 [packed = true]; + + repeated sint64 repeated_sint64 = 16; +} + +message TestRequest { + int64 id = 1; + + TestBucket bucket = 2; + + TestProto2Message proto2_message = 18; + + repeated string repeated_strings = 3; + + repeated TestEnum repeated_enum = 17; + + repeated double repeated_double = 4; + + repeated float repeated_float = 5; + + repeated int64 repeated_int64 = 6; + + repeated uint64 repeated_uint64 = 7; + + repeated int32 repeated_int32 = 8; + + repeated fixed64 repeated_fixed64 = 9; + + repeated fixed32 repeated_fixed32 = 10; + + repeated bool repeated_bool = 11; + + repeated uint32 repeated_uint32 = 12; + + repeated sfixed64 repeated_sfixed64 = 13; + + repeated sfixed32 repeated_sfixed32 = 14; + + repeated sint32 repeated_sint32 = 15; + + repeated sint64 repeated_sint64 = 16; +} + +message TestResponse { + repeated TestBucket buckets = 1; + + map sub_buckets = 3; + + TestBucket bucket_present = 4; + TestBucket bucket_absent = 5; + message SubMessage { + TestBucket bucket_present = 1; + TestBucket bucket_absent = 2; + } + SubMessage sub_message = 6; +} + +service AuditLoggingUtilTestService { + // AuditTest Method. + rpc AuditTest(TestRequest) returns (TestResponse); +} diff --git a/test/server/options_impl_test.cc b/test/server/options_impl_test.cc index 732ab9f03ed9..b03fdb15fee3 100644 --- a/test/server/options_impl_test.cc +++ b/test/server/options_impl_test.cc @@ -61,6 +61,13 @@ TEST_F(OptionsImplTest, InvalidMode) { EXPECT_THROW_WITH_REGEX(createOptionsImpl("envoy --mode bogus"), MalformedArgvException, "bogus"); } +TEST_F(OptionsImplTest, InvalidComponentLogLevelWithFineGrainLogging) { + EXPECT_THROW_WITH_REGEX( + createOptionsImpl("envoy --enable-fine-grain-logging --component-log-level http:info"), + MalformedArgvException, + "--component-log-level will not work with --enable-fine-grain-logging"); +} + TEST_F(OptionsImplTest, InvalidCommandLine) { EXPECT_THROW_WITH_REGEX(createOptionsImpl("envoy --blah"), MalformedArgvException, "Couldn't find match for argument"); @@ -98,7 +105,7 @@ TEST_F(OptionsImplTest, All) { "--file-flush-interval-msec 9000 " "--skip-hot-restart-on-no-parent " "--skip-hot-restart-parent-stats " - "--drain-time-s 60 --log-format [%v] --enable-fine-grain-logging --parent-shutdown-time-s 90 " + "--drain-time-s 60 --log-format [%v] --parent-shutdown-time-s 90 " "--log-path " "/foo/bar " "--disable-hot-restart --cpuset-threads --allow-unknown-static-fields " @@ -119,7 +126,7 @@ TEST_F(OptionsImplTest, All) { EXPECT_TRUE(options->skipHotRestartParentStats()); EXPECT_TRUE(options->skipHotRestartOnNoParent()); EXPECT_EQ("/foo/bar", options->logPath()); - EXPECT_EQ(true, options->enableFineGrainLogging()); + EXPECT_EQ(false, options->enableFineGrainLogging()); EXPECT_EQ("cluster", options->serviceClusterName()); EXPECT_EQ("node", options->serviceNodeName()); EXPECT_EQ("zone", options->serviceZone()); @@ -139,6 +146,10 @@ TEST_F(OptionsImplTest, All) { options = createOptionsImpl("envoy --mode init_only"); EXPECT_EQ(Server::Mode::InitOnly, options->mode()); + + // Tested separately because it's mutually exclusive with --component-log-level. + options = createOptionsImpl("envoy --enable-fine-grain-logging"); + EXPECT_EQ(true, options->enableFineGrainLogging()); } // Either variants of allow-unknown-[static-]-fields works. diff --git a/tools/base/requirements.txt b/tools/base/requirements.txt index effde79fa116..9e1bd10ef742 100644 --- a/tools/base/requirements.txt +++ b/tools/base/requirements.txt @@ -25,9 +25,9 @@ aio-api-bazel==0.0.2 \ --hash=sha256:56e36463d236e477b7e282f2d870185a0b978b50e2c3803c1ebf8b8ac4b18f5b \ --hash=sha256:d3f563b7698e874437d80538a89dd4d79bc37de2e850c846330ae456e3f21dcc # via -r requirements.in -aio-api-github==0.2.5 \ - --hash=sha256:301a357209831ac2bc0fb5c79f8b8795a5363da5cabc2229f10155bdb6d42f5d \ - --hash=sha256:3532d0892e875e8bb6b188c0beba4e8bac9d5147e249ce987bb2beef1e7b711e +aio-api-github==0.2.6 \ + --hash=sha256:71ca0e572a48eab09f3e54267b374fb3d53e246b83f6f23fe1f29f5560acdaed \ + --hash=sha256:be12d6bf612ce2abc85c695ce74547220636f96fe80d4e64cd2de8670db69c32 # via # -r requirements.in # envoy-base-utils @@ -88,83 +88,87 @@ aiofiles==24.1.0 \ --hash=sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c \ --hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5 # via envoy-github-release -aiohttp==3.9.5 \ - --hash=sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8 \ - --hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \ - --hash=sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475 \ - --hash=sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed \ - --hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \ - --hash=sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372 \ - --hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \ - --hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \ - --hash=sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1 \ - --hash=sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd \ - --hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \ - --hash=sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb \ - --hash=sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46 \ - --hash=sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de \ - --hash=sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78 \ - --hash=sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c \ - --hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \ - --hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \ - --hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \ - --hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \ - --hash=sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156 \ - --hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \ - --hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \ - --hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \ - --hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \ - --hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \ - --hash=sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da \ - --hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \ - --hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \ - --hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \ - --hash=sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8 \ - --hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \ - --hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \ - --hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \ - --hash=sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09 \ - --hash=sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031 \ - --hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \ - --hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \ - --hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \ - --hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \ - --hash=sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe \ - --hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \ - --hash=sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2 \ - --hash=sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1 \ - --hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \ - --hash=sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b \ - --hash=sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b \ - --hash=sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106 \ - --hash=sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac \ - --hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \ - --hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \ - --hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \ - --hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \ - --hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \ - --hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \ - --hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \ - --hash=sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a \ - --hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \ - --hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \ - --hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \ - --hash=sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24 \ - --hash=sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed \ - --hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \ - --hash=sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e \ - --hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \ - --hash=sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a \ - --hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \ - --hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \ - --hash=sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2 \ - --hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \ - --hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \ - --hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \ - --hash=sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11 \ - --hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \ - --hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \ - --hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f +aiohappyeyeballs==2.3.5 \ + --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ + --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 + # via aiohttp +aiohttp==3.10.3 \ + --hash=sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b \ + --hash=sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3 \ + --hash=sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27 \ + --hash=sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844 \ + --hash=sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7 \ + --hash=sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201 \ + --hash=sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee \ + --hash=sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f \ + --hash=sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696 \ + --hash=sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2 \ + --hash=sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f \ + --hash=sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f \ + --hash=sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8 \ + --hash=sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8 \ + --hash=sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68 \ + --hash=sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394 \ + --hash=sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e \ + --hash=sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7 \ + --hash=sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a \ + --hash=sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9 \ + --hash=sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7 \ + --hash=sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4 \ + --hash=sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab \ + --hash=sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec \ + --hash=sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c \ + --hash=sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1 \ + --hash=sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e \ + --hash=sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e \ + --hash=sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7 \ + --hash=sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752 \ + --hash=sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9 \ + --hash=sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5 \ + --hash=sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef \ + --hash=sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806 \ + --hash=sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17 \ + --hash=sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb \ + --hash=sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc \ + --hash=sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a \ + --hash=sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f \ + --hash=sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93 \ + --hash=sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1 \ + --hash=sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09 \ + --hash=sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57 \ + --hash=sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad \ + --hash=sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1 \ + --hash=sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88 \ + --hash=sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9 \ + --hash=sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9 \ + --hash=sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06 \ + --hash=sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1 \ + --hash=sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2 \ + --hash=sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299 \ + --hash=sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac \ + --hash=sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204 \ + --hash=sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5 \ + --hash=sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f \ + --hash=sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f \ + --hash=sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2 \ + --hash=sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f \ + --hash=sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6 \ + --hash=sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272 \ + --hash=sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e \ + --hash=sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db \ + --hash=sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f \ + --hash=sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752 \ + --hash=sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a \ + --hash=sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e \ + --hash=sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c \ + --hash=sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279 \ + --hash=sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc \ + --hash=sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b \ + --hash=sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf \ + --hash=sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa \ + --hash=sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21 \ + --hash=sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73 \ + --hash=sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189 # via # -r requirements.in # aio-api-github @@ -239,59 +243,74 @@ certifi==2024.7.4 \ # via # aioquic # requests -cffi==1.16.0 \ - --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ - --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ - --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ - --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ - --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ - --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ - --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ - --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ - --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ - --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ - --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ - --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ - --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ - --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ - --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ - --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ - --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ - --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ - --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ - --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ - --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ - --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ - --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ - --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ - --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ - --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ - --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ - --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ - --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ - --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ - --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ - --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ - --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ - --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ - --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ - --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ - --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ - --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ - --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ - --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ - --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ - --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ - --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ - --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ - --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ - --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ - --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ - --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ - --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ - --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ - --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ - --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 +cffi==1.17.0 \ + --hash=sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f \ + --hash=sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab \ + --hash=sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499 \ + --hash=sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058 \ + --hash=sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693 \ + --hash=sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb \ + --hash=sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377 \ + --hash=sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885 \ + --hash=sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2 \ + --hash=sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401 \ + --hash=sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4 \ + --hash=sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b \ + --hash=sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59 \ + --hash=sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f \ + --hash=sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c \ + --hash=sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555 \ + --hash=sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa \ + --hash=sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424 \ + --hash=sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb \ + --hash=sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2 \ + --hash=sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8 \ + --hash=sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e \ + --hash=sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9 \ + --hash=sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82 \ + --hash=sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828 \ + --hash=sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759 \ + --hash=sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc \ + --hash=sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118 \ + --hash=sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf \ + --hash=sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932 \ + --hash=sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a \ + --hash=sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29 \ + --hash=sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206 \ + --hash=sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2 \ + --hash=sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c \ + --hash=sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c \ + --hash=sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0 \ + --hash=sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a \ + --hash=sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195 \ + --hash=sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6 \ + --hash=sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9 \ + --hash=sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc \ + --hash=sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb \ + --hash=sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0 \ + --hash=sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7 \ + --hash=sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb \ + --hash=sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a \ + --hash=sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492 \ + --hash=sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720 \ + --hash=sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42 \ + --hash=sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7 \ + --hash=sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d \ + --hash=sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d \ + --hash=sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb \ + --hash=sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4 \ + --hash=sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2 \ + --hash=sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b \ + --hash=sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8 \ + --hash=sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e \ + --hash=sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204 \ + --hash=sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3 \ + --hash=sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150 \ + --hash=sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4 \ + --hash=sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 \ + --hash=sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e \ + --hash=sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb \ + --hash=sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91 # via # -r requirements.in # cryptography @@ -478,9 +497,9 @@ docutils==0.20.1 \ # envoy-docs-sphinx-runner # sphinx # sphinx-rtd-theme -envoy-base-utils==0.5.1 \ - --hash=sha256:477ab036d4e523a962f7f37382ed55d8b04c78efbcc3db276b5e1711f4838d29 \ - --hash=sha256:fa4a3f2ea55e558979b99ab7d0baeb4cd30a9eb50c3f7cf63e6b2129625e4d58 +envoy-base-utils==0.5.2 \ + --hash=sha256:29d1384aded102b1c2cbfab44b07dbb35bc08a181e9e87a990ea0b90540ea54c \ + --hash=sha256:facd099692d3ec02d0597a2a2ff002a1702ccea1da31633d171420a791265e09 # via # -r requirements.in # envoy-code-check @@ -496,9 +515,9 @@ envoy-code-check==0.5.13 \ --hash=sha256:58c31be3ba1a3273eec8a76d1dcfe1a3ae5eae4730ca9d70a85fec0d641846c4 \ --hash=sha256:6c568d477642abdf7b41a0b6a5bb21fd480d92e500c53120837a01d4436d8591 # via -r requirements.in -envoy-dependency-check==0.1.12 \ - --hash=sha256:4673cb4cf9c0e2c55b2a0e0b39df3b8df9993d6524c6edb9527d3c8fb1ec24e2 \ - --hash=sha256:7443e530a2a9155d1e114b8a99d9355bbbe73005b0c96ee653907912ae368f3c +envoy-dependency-check==0.1.13 \ + --hash=sha256:4337b9c4129ae723dc92f70733b167a8dde187368d873687c6c54732d6fb5e48 \ + --hash=sha256:795e885eccd072d7878dc8ce11fe9f84761f0e449603e583fdab5e9e17111af2 # via -r requirements.in envoy-distribution-distrotest==0.0.10 \ --hash=sha256:83e912c48da22eb3e514fc1142247d33eb7ed0d59e94eca2ffbd178a26fbf808 \ @@ -549,9 +568,9 @@ fasteners==0.19 \ # via # google-apitools # gsutil -flake8==7.1.0 \ - --hash=sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a \ - --hash=sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5 +flake8==7.1.1 \ + --hash=sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38 \ + --hash=sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213 # via # -r requirements.in # envoy-code-check @@ -935,58 +954,64 @@ oauth2client==4.1.3 \ # via # gcs-oauth2-boto-plugin # google-apitools -orjson==3.10.6 \ - --hash=sha256:03c95484d53ed8e479cade8628c9cea00fd9d67f5554764a1110e0d5aa2de96e \ - --hash=sha256:05ac3d3916023745aa3b3b388e91b9166be1ca02b7c7e41045da6d12985685f0 \ - --hash=sha256:0943e4c701196b23c240b3d10ed8ecd674f03089198cf503105b474a4f77f21f \ - --hash=sha256:1335d4ef59ab85cab66fe73fd7a4e881c298ee7f63ede918b7faa1b27cbe5212 \ - --hash=sha256:1c680b269d33ec444afe2bdc647c9eb73166fa47a16d9a75ee56a374f4a45f43 \ - --hash=sha256:227df19441372610b20e05bdb906e1742ec2ad7a66ac8350dcfd29a63014a83b \ - --hash=sha256:30b0a09a2014e621b1adf66a4f705f0809358350a757508ee80209b2d8dae219 \ - --hash=sha256:3722fddb821b6036fd2a3c814f6bd9b57a89dc6337b9924ecd614ebce3271394 \ - --hash=sha256:446dee5a491b5bc7d8f825d80d9637e7af43f86a331207b9c9610e2f93fee22a \ - --hash=sha256:450e39ab1f7694465060a0550b3f6d328d20297bf2e06aa947b97c21e5241fbd \ - --hash=sha256:49e3bc615652617d463069f91b867a4458114c5b104e13b7ae6872e5f79d0844 \ - --hash=sha256:4bbc6d0af24c1575edc79994c20e1b29e6fb3c6a570371306db0993ecf144dc5 \ - --hash=sha256:5410111d7b6681d4b0d65e0f58a13be588d01b473822483f77f513c7f93bd3b2 \ - --hash=sha256:55d43d3feb8f19d07e9f01e5b9be4f28801cf7c60d0fa0d279951b18fae1932b \ - --hash=sha256:57985ee7e91d6214c837936dc1608f40f330a6b88bb13f5a57ce5257807da143 \ - --hash=sha256:61272a5aec2b2661f4fa2b37c907ce9701e821b2c1285d5c3ab0207ebd358d38 \ - --hash=sha256:633a3b31d9d7c9f02d49c4ab4d0a86065c4a6f6adc297d63d272e043472acab5 \ - --hash=sha256:64c81456d2a050d380786413786b057983892db105516639cb5d3ee3c7fd5148 \ - --hash=sha256:66680eae4c4e7fc193d91cfc1353ad6d01b4801ae9b5314f17e11ba55e934183 \ - --hash=sha256:697a35a083c4f834807a6232b3e62c8b280f7a44ad0b759fd4dce748951e70db \ - --hash=sha256:6eeb13218c8cf34c61912e9df2de2853f1d009de0e46ea09ccdf3d757896af0a \ - --hash=sha256:7275664f84e027dcb1ad5200b8b18373e9c669b2a9ec33d410c40f5ccf4b257e \ - --hash=sha256:738dbe3ef909c4b019d69afc19caf6b5ed0e2f1c786b5d6215fbb7539246e4c6 \ - --hash=sha256:79b9b9e33bd4c517445a62b90ca0cc279b0f1f3970655c3df9e608bc3f91741a \ - --hash=sha256:874ce88264b7e655dde4aeaacdc8fd772a7962faadfb41abe63e2a4861abc3dc \ - --hash=sha256:95a0cce17f969fb5391762e5719575217bd10ac5a189d1979442ee54456393f3 \ - --hash=sha256:960db0e31c4e52fa0fc3ecbaea5b2d3b58f379e32a95ae6b0ebeaa25b93dfd34 \ - --hash=sha256:965a916373382674e323c957d560b953d81d7a8603fbeee26f7b8248638bd48b \ - --hash=sha256:9c1c4b53b24a4c06547ce43e5fee6ec4e0d8fe2d597f4647fc033fd205707365 \ - --hash=sha256:a2debd8ddce948a8c0938c8c93ade191d2f4ba4649a54302a7da905a81f00b56 \ - --hash=sha256:a6ea7afb5b30b2317e0bee03c8d34c8181bc5a36f2afd4d0952f378972c4efd5 \ - --hash=sha256:ac3045267e98fe749408eee1593a142e02357c5c99be0802185ef2170086a863 \ - --hash=sha256:b1ec490e10d2a77c345def52599311849fc063ae0e67cf4f84528073152bb2ba \ - --hash=sha256:b6f3d167d13a16ed263b52dbfedff52c962bfd3d270b46b7518365bcc2121eed \ - --hash=sha256:bb1f28a137337fdc18384079fa5726810681055b32b92253fa15ae5656e1dddb \ - --hash=sha256:bf2fbbce5fe7cd1aa177ea3eab2b8e6a6bc6e8592e4279ed3db2d62e57c0e1b2 \ - --hash=sha256:c27bc6a28ae95923350ab382c57113abd38f3928af3c80be6f2ba7eb8d8db0b0 \ - --hash=sha256:c2c116072a8533f2fec435fde4d134610f806bdac20188c7bd2081f3e9e0133f \ - --hash=sha256:caff75b425db5ef8e8f23af93c80f072f97b4fb3afd4af44482905c9f588da28 \ - --hash=sha256:d27456491ca79532d11e507cadca37fb8c9324a3976294f68fb1eff2dc6ced5a \ - --hash=sha256:d40f839dddf6a7d77114fe6b8a70218556408c71d4d6e29413bb5f150a692ff7 \ - --hash=sha256:df25d9271270ba2133cc88ee83c318372bdc0f2cd6f32e7a450809a111efc45c \ - --hash=sha256:e060748a04cccf1e0a6f2358dffea9c080b849a4a68c28b1b907f272b5127e9b \ - --hash=sha256:e54b63d0a7c6c54a5f5f726bc93a2078111ef060fec4ecbf34c5db800ca3b3a7 \ - --hash=sha256:ea2977b21f8d5d9b758bb3f344a75e55ca78e3ff85595d248eee813ae23ecdfb \ - --hash=sha256:eadc8fd310edb4bdbd333374f2c8fec6794bbbae99b592f448d8214a5e4050c0 \ - --hash=sha256:f215789fb1667cdc874c1b8af6a84dc939fd802bf293a8334fce185c79cd359b \ - --hash=sha256:f710f346e4c44a4e8bdf23daa974faede58f83334289df80bc9cd12fe82573c7 \ - --hash=sha256:f759503a97a6ace19e55461395ab0d618b5a117e8d0fbb20e70cfd68a47327f2 \ - --hash=sha256:fb0ee33124db6eaa517d00890fc1a55c3bfe1cf78ba4a8899d71a06f2d6ff5c7 \ - --hash=sha256:fd502f96bf5ea9a61cbc0b2b5900d0dd68aa0da197179042bdd2be67e51a1e4b +orjson==3.10.7 \ + --hash=sha256:084e537806b458911137f76097e53ce7bf5806dda33ddf6aaa66a028f8d43a23 \ + --hash=sha256:09b2d92fd95ad2402188cf51573acde57eb269eddabaa60f69ea0d733e789fe9 \ + --hash=sha256:0fa5886854673222618638c6df7718ea7fe2f3f2384c452c9ccedc70b4a510a5 \ + --hash=sha256:11748c135f281203f4ee695b7f80bb1358a82a63905f9f0b794769483ea854ad \ + --hash=sha256:1193b2416cbad1a769f868b1749535d5da47626ac29445803dae7cc64b3f5c98 \ + --hash=sha256:144888c76f8520e39bfa121b31fd637e18d4cc2f115727865fdf9fa325b10412 \ + --hash=sha256:1d9c0e733e02ada3ed6098a10a8ee0052dd55774de3d9110d29868d24b17faa1 \ + --hash=sha256:23820a1563a1d386414fef15c249040042b8e5d07b40ab3fe3efbfbbcbcb8864 \ + --hash=sha256:33cfb96c24034a878d83d1a9415799a73dc77480e6c40417e5dda0710d559ee6 \ + --hash=sha256:348bdd16b32556cf8d7257b17cf2bdb7ab7976af4af41ebe79f9796c218f7e91 \ + --hash=sha256:34a566f22c28222b08875b18b0dfbf8a947e69df21a9ed5c51a6bf91cfb944ac \ + --hash=sha256:3dcfbede6737fdbef3ce9c37af3fb6142e8e1ebc10336daa05872bfb1d87839c \ + --hash=sha256:430ee4d85841e1483d487e7b81401785a5dfd69db5de01314538f31f8fbf7ee1 \ + --hash=sha256:44a96f2d4c3af51bfac6bc4ef7b182aa33f2f054fd7f34cc0ee9a320d051d41f \ + --hash=sha256:479fd0844ddc3ca77e0fd99644c7fe2de8e8be1efcd57705b5c92e5186e8a250 \ + --hash=sha256:480f455222cb7a1dea35c57a67578848537d2602b46c464472c995297117fa09 \ + --hash=sha256:4829cf2195838e3f93b70fd3b4292156fc5e097aac3739859ac0dcc722b27ac0 \ + --hash=sha256:4b6146e439af4c2472c56f8540d799a67a81226e11992008cb47e1267a9b3225 \ + --hash=sha256:4e6c3da13e5a57e4b3dca2de059f243ebec705857522f188f0180ae88badd354 \ + --hash=sha256:5b24a579123fa884f3a3caadaed7b75eb5715ee2b17ab5c66ac97d29b18fe57f \ + --hash=sha256:6b0dd04483499d1de9c8f6203f8975caf17a6000b9c0c54630cef02e44ee624e \ + --hash=sha256:6ea2b2258eff652c82652d5e0f02bd5e0463a6a52abb78e49ac288827aaa1469 \ + --hash=sha256:7122a99831f9e7fe977dc45784d3b2edc821c172d545e6420c375e5a935f5a1c \ + --hash=sha256:74f4544f5a6405b90da8ea724d15ac9c36da4d72a738c64685003337401f5c12 \ + --hash=sha256:75ef0640403f945f3a1f9f6400686560dbfb0fb5b16589ad62cd477043c4eee3 \ + --hash=sha256:76ac14cd57df0572453543f8f2575e2d01ae9e790c21f57627803f5e79b0d3c3 \ + --hash=sha256:77d325ed866876c0fa6492598ec01fe30e803272a6e8b10e992288b009cbe149 \ + --hash=sha256:7c4c17f8157bd520cdb7195f75ddbd31671997cbe10aee559c2d613592e7d7eb \ + --hash=sha256:7db8539039698ddfb9a524b4dd19508256107568cdad24f3682d5773e60504a2 \ + --hash=sha256:8272527d08450ab16eb405f47e0f4ef0e5ff5981c3d82afe0efd25dcbef2bcd2 \ + --hash=sha256:82763b46053727a7168d29c772ed5c870fdae2f61aa8a25994c7984a19b1021f \ + --hash=sha256:8a9c9b168b3a19e37fe2778c0003359f07822c90fdff8f98d9d2a91b3144d8e0 \ + --hash=sha256:8de062de550f63185e4c1c54151bdddfc5625e37daf0aa1e75d2a1293e3b7d9a \ + --hash=sha256:974683d4618c0c7dbf4f69c95a979734bf183d0658611760017f6e70a145af58 \ + --hash=sha256:9ea2c232deedcb605e853ae1db2cc94f7390ac776743b699b50b071b02bea6fe \ + --hash=sha256:a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09 \ + --hash=sha256:a763bc0e58504cc803739e7df040685816145a6f3c8a589787084b54ebc9f16e \ + --hash=sha256:a7e19150d215c7a13f39eb787d84db274298d3f83d85463e61d277bbd7f401d2 \ + --hash=sha256:ac7cf6222b29fbda9e3a472b41e6a5538b48f2c8f99261eecd60aafbdb60690c \ + --hash=sha256:b48b3db6bb6e0a08fa8c83b47bc169623f801e5cc4f24442ab2b6617da3b5313 \ + --hash=sha256:b58d3795dafa334fc8fd46f7c5dc013e6ad06fd5b9a4cc98cb1456e7d3558bd6 \ + --hash=sha256:bdbb61dcc365dd9be94e8f7df91975edc9364d6a78c8f7adb69c1cdff318ec93 \ + --hash=sha256:bf6ba8ebc8ef5792e2337fb0419f8009729335bb400ece005606336b7fd7bab7 \ + --hash=sha256:c31008598424dfbe52ce8c5b47e0752dca918a4fdc4a2a32004efd9fab41d866 \ + --hash=sha256:cb61938aec8b0ffb6eef484d480188a1777e67b05d58e41b435c74b9d84e0b9c \ + --hash=sha256:d2d9f990623f15c0ae7ac608103c33dfe1486d2ed974ac3f40b693bad1a22a7b \ + --hash=sha256:d352ee8ac1926d6193f602cbe36b1643bbd1bbcb25e3c1a657a4390f3000c9a5 \ + --hash=sha256:d374d36726746c81a49f3ff8daa2898dccab6596864ebe43d50733275c629175 \ + --hash=sha256:de817e2f5fc75a9e7dd350c4b0f54617b280e26d1631811a43e7e968fa71e3e9 \ + --hash=sha256:e724cebe1fadc2b23c6f7415bad5ee6239e00a69f30ee423f319c6af70e2a5c0 \ + --hash=sha256:e72591bcfe7512353bd609875ab38050efe3d55e18934e2f18950c108334b4ff \ + --hash=sha256:e76be12658a6fa376fcd331b1ea4e58f5a06fd0220653450f0d415b8fd0fbe20 \ + --hash=sha256:eb8d384a24778abf29afb8e41d68fdd9a156cf6e5390c04cc07bbc24b89e98b5 \ + --hash=sha256:ed350d6978d28b92939bfeb1a0570c523f6170efc3f0a0ef1f1df287cd4f4960 \ + --hash=sha256:eef44224729e9525d5261cc8d28d6b11cafc90e6bd0be2157bde69a52ec83024 \ + --hash=sha256:f4db56635b58cd1a200b0a23744ff44206ee6aa428185e2b6c4a65b3197abdcd \ + --hash=sha256:fdf5197a21dd660cf19dfd2a3ce79574588f8f5e2dbf21bda9ee2d2b46924d84 # via # -r requirements.in # envoy-base-utils @@ -1019,18 +1044,18 @@ ply==3.11 \ --hash=sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3 \ --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce # via -r requirements.in -protobuf==5.27.2 \ - --hash=sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505 \ - --hash=sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b \ - --hash=sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38 \ - --hash=sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863 \ - --hash=sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470 \ - --hash=sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6 \ - --hash=sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce \ - --hash=sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca \ - --hash=sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5 \ - --hash=sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e \ - --hash=sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714 +protobuf==5.27.3 \ + --hash=sha256:043853dcb55cc262bf2e116215ad43fa0859caab79bb0b2d31b708f128ece035 \ + --hash=sha256:16ddf3f8c6c41e1e803da7abea17b1793a97ef079a912e42351eabb19b2cffe7 \ + --hash=sha256:68248c60d53f6168f565a8c76dc58ba4fa2ade31c2d1ebdae6d80f969cdc2d4f \ + --hash=sha256:82460903e640f2b7e34ee81a947fdaad89de796d324bcbc38ff5430bcdead82c \ + --hash=sha256:8572c6533e544ebf6899c360e91d6bcbbee2549251643d32c52cf8a5de295ba5 \ + --hash=sha256:a55c48f2a2092d8e213bd143474df33a6ae751b781dd1d1f4d953c128a415b25 \ + --hash=sha256:af7c0b7cfbbb649ad26132e53faa348580f844d9ca46fd3ec7ca48a1ea5db8a1 \ + --hash=sha256:b8a994fb3d1c11156e7d1e427186662b64694a62b55936b2b9348f0a7c6625ce \ + --hash=sha256:c2a105c24f08b1e53d6c7ffe69cb09d0031512f0b72f812dd4005b8112dbe91e \ + --hash=sha256:c84eee2c71ed83704f1afbf1a85c3171eab0fd1ade3b399b3fad0884cbcca8bf \ + --hash=sha256:dcb307cd4ef8fec0cf52cb9105a03d06fbb5275ce6d84a6ae33bc6cf84e0a07b # via # -r requirements.in # envoy-base-utils @@ -1142,58 +1167,60 @@ pytz==2024.1 \ pyu2f==0.1.5 \ --hash=sha256:a3caa3a11842fc7d5746376f37195e6af5f17c0a15737538bb1cebf656fb306b # via google-reauth -pyyaml==6.0.1 \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ - --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ - --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ - --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ - --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ - --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ - --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ - --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ - --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ - --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ - --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ - --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ - --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ - --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ - --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ - --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ - --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ - --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ - --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ - --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ - --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ - --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ - --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ - --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ - --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ - --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ - --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ - --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ - --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ - --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ - --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ - --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ - --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ - --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ - --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ - --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ - --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ - --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ - --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ - --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ - --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f +pyyaml==6.0.2 \ + --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \ + --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \ + --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \ + --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \ + --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \ + --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \ + --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \ + --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \ + --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \ + --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \ + --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \ + --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \ + --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \ + --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \ + --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \ + --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \ + --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \ + --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \ + --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \ + --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \ + --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \ + --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \ + --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \ + --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \ + --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \ + --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \ + --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \ + --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \ + --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \ + --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \ + --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \ + --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \ + --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \ + --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \ + --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \ + --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \ + --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \ + --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \ + --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \ + --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \ + --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \ + --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \ + --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \ + --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \ + --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \ + --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \ + --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \ + --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \ + --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \ + --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \ + --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \ + --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ + --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 # via # -r requirements.in # aio-core @@ -1671,7 +1698,7 @@ zstandard==0.23.0 \ # via envoy-base-utils # The following packages are considered to be unsafe in a requirements file: -setuptools==72.0.0 \ - --hash=sha256:5a0d9c6a2f332881a0153f629d8000118efd33255cfa802757924c53312c76da \ - --hash=sha256:98b4d786a12fadd34eabf69e8d014b84e5fc655981e4ff419994700434ace132 +setuptools==72.1.0 \ + --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ + --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec # via -r requirements.in diff --git a/tools/extensions/extensions_schema.yaml b/tools/extensions/extensions_schema.yaml index c1e9f4ffdb1d..c8f589a5fa67 100644 --- a/tools/extensions/extensions_schema.yaml +++ b/tools/extensions/extensions_schema.yaml @@ -22,6 +22,7 @@ builtin: - envoy.matching.inputs.transport_protocol - envoy.matching.inputs.application_protocol - envoy.matching.inputs.filter_state +- envoy.matching.inputs.dynamic_metadata - envoy.matching.inputs.uri_san - envoy.matching.inputs.dns_san - envoy.matching.inputs.subject diff --git a/tools/gcs/BUILD b/tools/gcs/BUILD new file mode 100644 index 000000000000..c42a57de4cfc --- /dev/null +++ b/tools/gcs/BUILD @@ -0,0 +1,16 @@ +load("@envoy_repo//:path.bzl", "PATH") +load("//bazel:envoy_build_system.bzl", "envoy_package") + +licenses(["notice"]) # Apache 2 + +envoy_package() + +sh_binary( + name = "upload", + srcs = ["upload.sh"], + data = ["//tools/gsutil"], + env = { + "ENVOY_SOURCE_DIR": PATH, + "GSUTIL": "$(location //tools/gsutil)", + }, +) diff --git a/ci/upload_gcs_artifact.sh b/tools/gcs/upload.sh similarity index 52% rename from ci/upload_gcs_artifact.sh rename to tools/gcs/upload.sh index f088f60299b8..f6e26516ce99 100755 --- a/ci/upload_gcs_artifact.sh +++ b/tools/gcs/upload.sh @@ -2,16 +2,43 @@ set -e -o pipefail +GCS_ARTIFACT_BUCKET="${1:-}" +GCP_SERVICE_ACCOUNT_KEY_PATH="${2:-}" +UPLOAD_DIRECTORY="${3:-}" +TARGET_SUFFIX="${4:-}" +REDIRECT_PATH="${5:-}" + +# +# $ bazel run //tools/gcs:upload BUCKETNAME KEY_PATH REDIRECT_PATH + + +if [[ -z "${GSUTIL}" ]]; then + echo "GSUTIL is not set, not uploading artifacts." + exit 1 +fi + +if [[ -z "${ENVOY_SOURCE_DIR}" ]]; then + echo "ENVOY_SOURCE_DIR is not set, not uploading artifacts." + exit 1 +fi + if [[ -z "${GCS_ARTIFACT_BUCKET}" ]]; then echo "Artifact bucket is not set, not uploading artifacts." exit 1 fi -read -ra BAZEL_STARTUP_OPTIONS <<< "${BAZEL_STARTUP_OPTION_LIST:-}" -read -ra BAZEL_BUILD_OPTIONS <<< "${BAZEL_BUILD_OPTION_LIST:-}" - if [[ ! -s "${GCP_SERVICE_ACCOUNT_KEY_PATH}" ]]; then - echo "GCP key is not set, not uploading artifacts." + echo "GCP key path is not set, not uploading artifacts." + exit 1 +fi + +if [[ -z "${UPLOAD_DIRECTORY}" ]]; then + echo "UPLOAD_DIRECTORY is not set, not uploading artifacts." + exit 1 +fi + +if [[ -z "${TARGET_SUFFIX}" ]]; then + echo "TARGET_SUFFIX is not set, not uploading artifacts." exit 1 fi @@ -20,13 +47,6 @@ cat < ~/.boto gs_service_key_file=${GCP_SERVICE_ACCOUNT_KEY_PATH} EOF -SOURCE_DIRECTORY="$1" -TARGET_SUFFIX="$2" - -if [ ! -d "${SOURCE_DIRECTORY}" ]; then - echo "ERROR: ${SOURCE_DIRECTORY} is not found." - exit 1 -fi # Upload to the last commit sha (first 7 chars) # the bucket is either `envoy-postsubmit` or `envoy-pr` @@ -40,32 +60,31 @@ fi # https://storage.googleapis.com/envoy-pr/28462/docs/index.html # -UPLOAD_PATH="$(git rev-parse HEAD | head -c7)" -REDIRECT_PATH="${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER:-${BUILD_SOURCEBRANCHNAME}}" +UPLOAD_PATH="$(git -C "${ENVOY_SOURCE_DIR}" rev-parse HEAD | head -c7)" GCS_LOCATION="${GCS_ARTIFACT_BUCKET}/${UPLOAD_PATH}/${TARGET_SUFFIX}" echo "Uploading to gs://${GCS_LOCATION} ..." -bazel "${BAZEL_STARTUP_OPTIONS[@]}" run "${BAZEL_BUILD_OPTIONS[@]}" \ - //tools/gsutil \ - -- -mq rsync \ - -dr "${SOURCE_DIRECTORY}" \ +"${GSUTIL}" \ + -mq rsync \ + -dr "${UPLOAD_DIRECTORY}" \ "gs://${GCS_LOCATION}" +if [[ -z "${REDIRECT_PATH}" ]]; then + echo "Artifacts uploaded to: https://storage.googleapis.com/${GCS_LOCATION}" >&2 + exit 0 +fi + TMP_REDIRECT="/tmp/redirect/${REDIRECT_PATH}/${TARGET_SUFFIX}" mkdir -p "$TMP_REDIRECT" echo "" \ > "${TMP_REDIRECT}/index.html" GCS_REDIRECT="${GCS_ARTIFACT_BUCKET}/${REDIRECT_PATH}/${TARGET_SUFFIX}" -echo "Uploading redirect to gs://${GCS_REDIRECT} ..." -bazel "${BAZEL_STARTUP_OPTIONS[@]}" run "${BAZEL_BUILD_OPTIONS[@]}" \ - //tools/gsutil \ - -- -h "Cache-Control:no-cache,max-age=0" \ +echo "Uploading redirect to gs://${GCS_REDIRECT} ..." >&2 +"${GSUTIL}" \ + -h "Cache-Control:no-cache,max-age=0" \ -mq rsync \ -dr "${TMP_REDIRECT}" \ "gs://${GCS_REDIRECT}" -if [[ "${COVERAGE_FAILED}" -eq 1 ]]; then - echo "##vso[task.logissue type=error]Coverage failed, check artifact at: https://storage.googleapis.com/${GCS_LOCATION}/index.html" -fi - -echo "Artifacts uploaded to: https://storage.googleapis.com/${GCS_LOCATION}/index.html" +echo "Artifacts uploaded to: https://storage.googleapis.com/${GCS_REDIRECT}/index.html" >&2 +echo "https://storage.googleapis.com/${GCS_REDIRECT}/index.html" diff --git a/tools/spelling/check_spelling_pedantic.py b/tools/spelling/check_spelling_pedantic.py index d94f60a1aed6..082122dcf417 100755 --- a/tools/spelling/check_spelling_pedantic.py +++ b/tools/spelling/check_spelling_pedantic.py @@ -106,6 +106,9 @@ def cmp(x, y): # RST code block marker. RST_CODE_BLOCK = '.. code-block::' +# RST literal include. +RST_LITERAL_INCLUDE = '.. literalinclude::' + # Path names. ABSPATH = re.compile(r'(?:\s|^)((/[A-Za-z0-9_.*-]+)+)(?:\s|$)') FILEREF = re.compile(r'(?:\s|^)([A-Za-z0-9_./-]+\.(cc|js|h|py|sh))(?:\s|$)') @@ -649,7 +652,7 @@ def extract_comments(lines): comments.append(Comment(line=line_idx, col=col, text=text, last_on_line=last_on_line)) # Handle control statements and filter out comments that are part of - # RST code block directives. + # RST code block and literal include directives. result = [] n = 0 nc = len(comments) @@ -687,7 +690,8 @@ def extract_comments(lines): break n += 1 - elif text.strip().startswith(RST_CODE_BLOCK): + elif text.strip().startswith(RST_CODE_BLOCK) or text.strip().startswith( + RST_LITERAL_INCLUDE): # Start of a code block. indent = len(INDENT.search(text).group(1)) last_line = comments[n].line diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index eff88c22e99e..263479eba905 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -27,6 +27,7 @@ BACKTRACE BEL BBR BIDIRECTIONAL +CCL ECN ECS EKS @@ -38,6 +39,8 @@ BPF Bdecoded Bencoded CIO +cbegin +cend deadcode DFP Dynatrace @@ -93,6 +96,7 @@ OWS Preconnecting RCVBUF RTCP +RTLD RTP SOH SPC @@ -306,6 +310,7 @@ NOAUTH NOCHECKRESP NODATA NODELAY +NODELETE NOLINT NOLINTNEXTLINE NONAME @@ -324,6 +329,9 @@ middlewildcard monostate mpd mutators +mybucket +myobject +myproject na oghttp OID @@ -374,6 +382,7 @@ RDS README RECVDSTADDR RECVPKTINFO +RECVTOS REFNIL REQ REUSEADDR @@ -721,6 +730,9 @@ dgst dir dirname djb +dlclose +dlopen +dlsym downcalls downcasted downcased @@ -1230,6 +1242,7 @@ rollout roundtrip rpcs rq +rtest rtrim rtt ruleset @@ -1464,6 +1477,7 @@ virtualize virtualized vptr vtable +vtest vtt wakeup wakeups